当有空格时,我的程序很好地评估后缀表达式,但是无法评估像'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++;
}
}
}
答案 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)
很容易解决这个问题,并且它增加了所显示代码的复杂性。
如果您使用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;
}