2017-10-21 34 views
1

私のプログラムは、空白がある場合は後置式をよく評価しますが、空白がない'56 * 'のような単純なものは評価できません。それ、どうやったら出来るの?空白がない場合にpostfixを評価するには?

また、 "1.2e3 -3.4e-1 /"はe表記の(-1)を理解できず+1として扱います。これは別の問題です。私はそれに適応するコードを調整する必要があります。

#include <stdio.h> 
#include <ctype.h> 
#include <math.h> 
#include <stdlib.h> 

#define SIZE 50 /* Size of Stack */ 

double s[SIZE]; 
int peak=-1; /* Global declarations */ 
char pofx[50]; 

double pop() 
{      /* Function for POP operation */ 
    return(s[peak--]); 
} 

double push(double elem) { 
    if (peak + 1 >= SIZE) { 
    printf("Stack overflow\n"); 
    return 0; 
    } 
    s[++peak] = elem; 
} 

void main() 
{       /* Main Program */ 
    printf("Enter the Postfix Expression:"); 
    // fgets(pofx,100,stdin); // 100?? 
    fgets(pofx, sizeof pofx, stdin); // better 
    postfixtoresult(); 
    printf("Result: %lf\n",s[peak]); 
} 

void postfixtoresult() 
{    
    int i=0; 
    const char *st = pofx; 

    while (*st) { 
    char *end; //location to store end of FP parsing 
    double value = strtod(st, &end); 
    if (end > st) { 
     push(value); 
     st = end; 
    } else if (isspace((unsigned char) *st)) { 
     st++; 
    } else { 
     switch (*st) { 
     case '+':push(pop() + pop());break; // pop order irrelevant 
     case '-':{ double t = pop(); push(pop() - t);break; } // pop order    relevant 
     case '*':push(pop() * pop());break; // pop order irrelevant 
     case '/':{ double u = pop(); push(pop()/u);break; } // pop order relevant 
     case '^':{ double v = pop(); push(pow(pop(),v));break; } // pop order relevant 

     default: { 
      printf("Input invalid operator: character code %d\n", *st); 
      return 0; 
     } 
     } // end switch 
     st++; 
    } 
    }  
} 
+0

、またはあなたができるかどうか複数桁の番号を入力してください。一桁の数字だけを許可している場合は、数字を数字として読み取ることができます( 'strtod() 'を使用しないでください)。自動的に' 56 * 'から' 5'、 '6'、' * 'を取得します。複数桁の数値を許可すると、 '56 *'はエラーになります。 '*'演算子が使用するのに十分な数のスタックがありません。あなたはどちらかを選ぶでしょう - それは大したことではありません。入力に1桁の数字のみを許可することは、かなり制限的です。ユーザーが空白で数字を区切っていることを主張することをお勧めします。 –

+0

ありがとう@JonathanLeffler。空白の問題を解決するために入力を1桁で保持し、同時に負の整数としてeの表記を受け入れることにした場合、コードをどのように変更すればよいですか? –

+0

現在 'strtod()'と呼ばれているコードをやり直す必要があります。しかし、それは率直に言って1桁の数字で指数表記をすることはできません。サインはより簡単に処理できます。 –

答えて

0

あなたは、あなたが最後の文字をungetc(3)する必要があり、おそらく、次の文字が新しいトークンの一部にすることはできませんまで有効な文字を食べる貪欲スキャナを構築する必要があります。

以下は、整数(符号付きまたは符号なし)を解析し、スペース(または符号)を正しく扱うスキャナです(私は思っています:)。自由に使用したり、必要に応じて変更してください。数字の前にプラス記号またはマイナス記号が付いていることに気をつけてください(スペースを挿入することで解き放つことができます)

もっと複雑なもの(浮動小数点数など)を解析する必要がある場合は、スキャナジェネレータlex(1)/flex(1)を読んで使用してください。

#include <stdio.h> 
#include <ctype.h> 

#define MAX_ID 64 /* must be at least two. Routine assumes that */ 

/* single chars include values 0..255 */ 
#define TOK_EOF  256 
#define TOK_ERR  257 
#define TOK_INT  258 

union tokenval { 
    int num; /* in case we return an integer */ 
    /* in case you scan other tokens with specific values, 
    * e.g. floating point numbers, you can add to this union. */ 
}; 

/* lexical scanner with one character of lookahead. 
* It recognises: 
* integers (regexp: [+-]?[0-9][0-9]*) 
* symbols (regexp: .) 
* comments (regexp: #.*\n) (these are ignored) 
*/ 
int scan(FILE *in, union tokenval *val) 
{ 
    int c; 
    int result = TOK_ERR; 

    while ((c = fgetc(in)) != EOF) { 

     if (isspace(c)) /* skip spaces */ 
      continue; 

     if (c == '#') { /* comment */ 
      while ((c = fgetc(in)) != EOF && (c != '\n')) continue; 
      /* c == EOF || c == '\n' */ 
      if (c == EOF) return TOK_EOF; 
      /* c == '\n' */ 
      continue; 
     } 

     if (isalpha(c)) { /* identifier */ 
      char *p = val->id; 
      size_t l = 1; 
      *p++ = c; /* add read char */ 
      while (isalnum(c = fgetc(in))) { 
       if (l < MAX_ID-1) { /* add only if we have space */ 
        *p++ = c; l++; 
       } 
      } 
      *p = '\0'; /* terminate the identifier properly */ 
      /* !isalnum(c) */ 
      ungetc(c, in); 
      return TOK_ID; 
     } 

     /* possible signed number */ 
     switch(c) { 
     case '+': /* possible signed number */ 
     case '-': 
      result = c; /* save the read char in result until we know 
          if we have a trailing number. */ 
      c = fgetc(in); 
     } 

     /* result in {TOK_ERR, '+', '-'} */ 
     if (isdigit(c)) { /* integer */ 
      val->num = c - '0'; 
      while (isdigit(c = fgetc(in))) { 
       val->num *= 10; 
       val->num += c - '0'; 
      } 
      /* !isdigit(c) */ 
      ungetc(c, in); 
      if (result == '-') val->num = -val->num; 
      return TOK_INT; 
     } 

     return result == TOK_ERR ? c : result; 
    } /* while */ 
    /* c == EOF */ 
    return TOK_EOF; 
} /* scan */ 

int main() { 
    int tok; 
    union tokenval val; 

#define EOL() puts("") 
#define P(tok) printf("[%s-%d]", #tok, (tok)) 
#define PS(tok) printf("['%c'-%d]\n", (tok), (tok)) 
    do { 
     tok = scan(stdin, &val); 
     switch(tok) { 
     case TOK_ERR: P(TOK_ERR); EOL(); break; 
     case TOK_INT: P(TOK_INT); printf(":%d\n", val.num); break; 
     case TOK_EOF: P(TOK_EOF); EOL(); break; 
     default: PS(tok); break; 
     } /* switch */ 
    } while (tok != TOK_EOF); 
} /* main */ 

浮動小数点数でe-1末尾サフィックスを扱っていない、示したスキャナとNOTE

問題(私はそれが含まれていない理由は)、これが可能なスキャナを必要とすることです有効な浮動小数点数(例えば、2.71 ---を読み、その後にe-を読み込んだ場合は、浮動小数点数を拡大するかどうかを決定するために別の文字を読み込む必要があります。 -符号の後に数字を入力すると、既に読み取った-e文字(その順序で)次のトークンが読み込まれたときにインクルードされます。 lex(1)/flex(1)でこの問題を解決するのは非常に簡単であるため、浮動小数点数の読み取りまたは読み取りが可能なスキャナは含まれておらず、コードが複雑になります。

注2

あなたはlex(1)/flex(1)を使用する場合は、上記スキャナ用のスキャナ仕様ができ:あなたが唯一のこれまでの1桁の数を入力するかどうかを決定する必要があり

%{ 

#include <stdio.h> 
#include <stdlib.h> 

/* single chars include values 0..255 */ 
#define TOK_EOF  0 
#define TOK_ERR  256 
#define TOK_INT  257 
#define TOK_DBL  258 
#define TOK_ID  259 

%} 

%% 
[+-]?[0-9][0-9]*          { return TOK_INT; /* integer */ } 
[+-]?([0-9]*\.[0-9]+|[0-9]+\.[0-9]*)([eE][+-]?[0-9]+)? { return TOK_DBL; /* double */ } 
#.*\n             ; /* comment, ignored */ 
[a-zA-Z][a-zA-Z0-9]*         { return TOK_ID; /* ident */ } 
[ \t\n]            ; /* space, ignored */ 
.              { return yytext[0]; /* the operator char */ } 
%% 

int main() 
{ 
    int tok; 
    do { 
     tok = yylex(); 
     switch(tok) { 
#define C(ptok) case TOK_##ptok: do{printf("[TOK_"#ptok"-%d]: %s\n", TOK_##ptok, yytext);}while(0) 
     C(EOF); break; 
     C(ERR); return 1; 
     C(INT); break; 
     C(DBL); break; 
     C(ID); break; 
     default: printf("['%c'-%d]\n", tok, tok); break; 
     } 
    } while(tok != TOK_EOF); 
    return 0; 
} /* main */ 

int yywrap() /* so we don't need to link with -ll */ 
{ 
    return 1; 
} 
関連する問題