我正在利用Bison和Flex创建一个基本的Lisp解释器,所以到目前为止我正在尝试制作一个也在读取一组括号的中缀加法器。出于某种原因,我的代码似乎每隔一段时间才能运行
lisp.l
%option noyywrap
%{
#include <stdlib.h>
#include <stdio.h>
#include "lisp.tab.h"
// #include "lisp.h"
#include <string.h>
#define YYSTYPE double
#define YY_DECL int yylex()
%}
%%
[ \t] ; {/* eat up whitespace */}
[0-9]+(\.[0-9]+)? {yylval.dval = atof(yytext); return DOUBLE;}
"+" {return ADD; }
"-" {return SUB; }
"/" {return DIVIDE; }
"*" {return MULTIPLY; }
"let" {return LET;}
"print" {return PRINT;}
"EQ" {return EQUAL;}
"LT" {return LESSTHAN;}
"LE" {return LESSTHANEQUAL;}
"GT" {return GREATERTHAN;}
"GE" {return GREATERTHANEQUAL;}
"NE" {return NOTEQUAL;}
"if" {return IF;}
";" {return IGNORE;}
[a-zA-Z]+ {return identifier;}
"(" {return LEFTPAR;}
")" {return RIGHTPAR;}
%%
lisp.y
%{
#include <stdio.h>
#include <stdlib.h>
// #include <map>
#include <string.h>
#include <math.h>
#include "lisp.tab.h"
// static std::map<std::string, double> symbolsMap;
// double symbolValMap(std::string symbol);
// void updateSymbolValMap(std::string symbol, double val);
extern int yylex();
extern FILE* yyin;
extern int yyparse();
void yyerror(const char* msg);
%}
%union {
double dval;
}
%token<dval> DOUBLE
%token<id> identifier
%token LET PRINT EQUAL LESSTHAN LESSTHANEQUAL GREATERTHAN GREATERTHANEQUAL
%token NOTEQUAL IF IGNORE LEFTPAR RIGHTPAR MULTIPLY DIVIDE SUB ADD
%type<dval> mixed_expression
%type<id> varName
%left SUB ADD MULTIPLY DIVIDE
%start program
%%
program:
| program line
;
line: '\n'
| mixed_expression '\n' {printf("\tResult: %f\n", $1);}
| '(stop)\n' {printf("bye!\n"); exit(0); }
;
mixed_expression: DOUBLE {$$ = $1;}
| LEFTPAR ADD mixed_expression mixed_expression RIGHTPAR {$$ = $3 + $4; printf("Result: %g","%1f", $$);}
| LEFTPAR SUB mixed_expression mixed_expression RIGHTPAR { $$ = $3 - $4; }
| LEFTPAR MULTIPLY mixed_expression mixed_expression RIGHTPAR {$$ = $3 * $4;}
| LEFTPAR DIVIDE mixed_expression mixed_expression RIGHTPAR {$$ = $3 / $4;}
| LEFTPAR mixed_expression RIGHTPAR { $$ = $2; }
;
%%
int main() {
yyin = stdin;
do {
yyparse();
} while(!feof(yyin));
return 0;
}
/*void updateSymbolValMap(std::string symbol, double val)
{
// symbolsMap[symbol] = val;
}
double symbolValMap(std::string symbol)
{
// return symbolsMap[symbol];
return 0;
}*/
void yyerror(char const* msg)
{
fprintf(stderr, "Parse error: %s\n", msg);
yyparse();
}
当我运行代码并传入参数时,输出以下内容:
(- 4 5)
Result: -1
(* 8 9)
Parse error: syntax error
Parse error: syntax error
Parse error: syntax error
Parse error: syntax error
生成文件
all = lisp
lisp.tab.c lisp.tab.h: lisp.y
bison -d lisp.y
lex.yy.c: lisp.l lisp.tab.h
flex lisp.l
lisp: lex.yy.c lisp.tab.c lisp.tab.h
gcc lisp.tab.c lex.yy.c -lm -o lisp
clean:
rm lisp lisp.tab.c lex.yy.c lisp.tab.h
无论如何,每隔一段时间我都会得到一个解析错误。任何帮助将不胜感激。
答案 0 :(得分:1)
为此起作用:
line: '\n'
| mixed_expression '\n' {printf("\tResult: %f\n", $1);}
您的词法分析器必须返回令牌\n
。但是你的词法分析器从来没有这样做过。实际上,换行字符与词法分析器中的任何规则都不匹配,因此它将执行default action(请参阅第三段),即将不匹配的字符打印到标准输出并继续查找令牌,而不向解析器传递任何内容。
此外,这根本不起作用:
| '(stop)\n' {printf("bye!\n"); exit(0); }
因为'(stop)\n'
不是C字符文字而且词法分析器肯定无法返回它。我怀疑你会收到lex的警告。将符号更改为"(stop)\n"
会使警告静音,但仍然不会产生可以从词法分析器返回的令牌。
还有许多其他问题,包括您使用的语义值标记(<id>
)未出现在%union
声明中,并且您将其声明为非{ -terminal(varName
),未定义。此外,优先级声明(%left SUB ADD MULTIPLY DIVIDE
)毫无意义,因为这些令牌不会进入shift-reduce冲突。