c - 没有空格时如何评估后缀?

标签 c stack evaluation postfix-mta

当有空格时,我的程序可以很好地计算后缀表达式,但是无法计算像 '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++;
    }
  }     
}   

最佳答案

你必须构建一个贪婪的扫描器,它会吃掉有效字符,直到下一个字符不能成为新 token 的一部分,然后你可能必须 ungetc(3) 最后一个字符。

下面是一个扫描器(带有一个 main() 函数来测试它)解析整数(有符号或无符号)并正确处理空格(或符号)(我认为 :))随意使用它或根据您的需要进行修改。注意数字前面的加号或减号会粘在上面(可以通过插入空格来取消粘住)

如果你需要解析更复杂的东西(比如 float )那么我会推荐你​​阅读和使用 lex(1)/flex(1) scanner发电机。

#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 */

注意

显示的扫描器的问题(以及我没有包括它的原因),不处理 float 中的 e-1 尾随后缀,是这需要一个扫描器能够回溯多个字符(如果您读取一个有效的 float --- 例如 2.71---,后跟 e- 您仍然需要读取另一个字符来决定如果你扩大你的 float ,那么如果你在 - 符号后没有得到数字,你必须推回已经读取的 -e 字符(按此顺序)在读取下一个标记时包含在内。我没有包含能够读取 float 的扫描仪,因为使用 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;
}

关于c - 没有空格时如何评估后缀?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46858920/

相关文章:

c - 如何将没有大小的二维数组传递给C中的函数

ios - 如何以编程方式终止 iOS 中的进程

c - C 中的 FILE 关键字到底是什么?

java - 如何从链表堆栈中推送或弹出

android - 如何在现有 Activity 之间切换?

scala - Scala 中如何评估方法?

c - if 语句、函数评估和编译器优化

用于简单表达式的 Javascript 解析器

c - 检查两个 int 值是否在彼此给定范围内的函数

c++ - ld : symbol(s) not found for architecture x86_64 on OSX 10. 9