Я бы использовал инструменты, которые доступны почти везде.
Мне нравится lex / yacc, потому что я их знаю, но везде есть эквиваленты.Поэтому, прежде чем писать сложный код, посмотрите, есть ли инструменты, которые помогут вам упростить его (проблемы, подобные этой, были решены раньше, поэтому не изобретайте колесо).
Итак, используя lex (flex) / yacc (бизон) Я бы сделал:
эл
%option noyywrap
Number [0-9]+
WhiteSpace [ \t\v\r]+
NewLine \n
%{
#include <stdio.h>
%}
%%
\( return '(';
\) return ')';
\+ return '+';
\- return '-';
\* return '*';
\/ return '/';
{Number} return 'N';
{NewLine} return '\n';
{WhiteSpace} /* Ignore */
. fprintf(stdout,"Error\n");exit(1);
%%
эй
%{
#include <stdio.h>
typedef double (*Operator)(double,double);
double mulOp(double l,double r) {return l*r;}
double divOp(double l,double r) {return l/r;}
double addOp(double l,double r) {return l+r;}
double subOp(double l,double r) {return l-r;}
extern char* yytext;
extern void yyerror(char const * msg);
%}
%union
{
Operator op;
double value;
}
%type <op> MultOp AddOp
%type <value> Expression MultExpr AddExpr BraceExpr
%%
Value: Expression '\n' { fprintf(stdout, "Result: %le\n", $1);return 0; }
Expression: AddExpr { $$ = $1;}
AddExpr: MultExpr { $$ = $1;}
| AddExpr AddOp MultExpr { $$ = ($2)($1, $3);}
MultExpr: BraceExpr { $$ = $1;}
| MultExpr MultOp BraceExpr { $$ = ($2)($1, $3);}
BraceExpr: '(' Expression ')' { $$ = $2;}
| 'N' { sscanf(yytext,"%le", &$$);}
MultOp: '*' { $$ = &mulOp;}
| '/' { $$ = &divOp;}
AddOp: '+' { $$ = &addOp;}
| '-' { $$ = &subOp;}
%%
void yyerror(char const * msg)
{
fprintf(stdout,"Error: %s", msg);
}
int main()
{
yyparse();
}
Сборка
> flex e.l
> bison e.y
> gcc *.c
> ./a.out
((5 + (3 + (7 * 2))) - (8 * 9)) / 72
Result: -6.944444e-01
>
Выше также обрабатываетобычные правила приоритета операторов:
Не из-за того, что я сделал, но кто-то умный разработал это давным-давно, и теперь вы можете легко получить грамматические правила для разбора выражений (просто google C Grammer
и извлеките нужную часть).
> ./a.out
2 + 3 * 4
Result: 1.400000e+01