2017-10-21 115 views
1

當有空格時,我的程序很好地評估了postfix表達式,但是沒有空格的簡單的'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 *'是一個錯誤;堆棧中沒有足夠的數字供'*'操作符使用。你會選擇一個或另一個 - 哪個並不重要。只允許輸入單個數字的數字是相當嚴格的。我建議你堅持讓用戶用空格分隔數字。 –

+0

謝謝@JonathanLeffler。如果我決定將輸入保持爲單個數字以解決無空白問題並同時接受e符號作爲負整數,那麼我該如何更改代碼? –

+0

您必須重做當前調用'strtod()'的代碼。但坦率地說,允許使用單個數字的指數符號是沒有意義的。標誌可以更容易地處理。 –

回答

0

你必須構建一個貪婪的掃描儀,吃有效的字符,直到下一個字符不能是新令牌的一部分,那麼你有可能是ungetc(3)的最後一個字符。

下面是一個掃描器(具有測試它的main()函數),用於解析整數(有符號或無符號)並正確處理空格(或符號)(我認爲:))隨意使用它或根據需要修改。請注意,數字前面的加號或減號會卡住它(您可以通過插入空格來解除粘連)

如果您需要解析更復雜的事物(如浮點數),那麼我會建議您閱讀和使用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在浮點數後後綴是,這需要能夠在掃描器回溯多個字符(如果您讀取了有效的浮點數 - 例如2.71 ---,然後是e-),您仍然需要閱讀另一個字符以決定是否放大浮點數,以防萬一您得到-後的數字符號,你必須推回已經讀取的-e char按照該順序)在讀取下一個標記時被包括。我沒有包含能夠讀取浮點數的掃描器,因爲使用lex(1)/flex(1)很容易解決這個問題,並且它增加了所示代碼的複雜性。

注2:

如果使用lex(1)/flex(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; 
} 
相關問題