如何在没有空格时评估postfix?

时间:2017-10-21 00:23:33

标签: c stack evaluation postfix

当有空格时,我的程序很好地评估后缀表达式,但是无法评估像'56 *'那样没有空格的简单表达式。我该怎么做?

另外,“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++;
    }
  }     
}   

1 个答案:

答案 0 :(得分: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尾随后缀,是因为这需要一个能够回溯多个char的扫描程序(如果你读了一个有效的浮点数---例如2.71 ---,然后是e-你仍然要读另一个字符来决定你是否扩大你的浮点数,所以如果你在-符号后没有得到数字,你必须在读取下一个标记时推回已经读取的-e字符(按此顺序)我没有包含扫描仪或读取浮点数,因为使用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;
}