Bison 和 Flex 代码每隔一段时间工作一次
Bison and Flex code works every other time
我正在使用 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", );}
| '(stop)\n' {printf("bye!\n"); exit(0); }
;
mixed_expression: DOUBLE {$$ = ;}
| LEFTPAR ADD mixed_expression mixed_expression RIGHTPAR {$$ = + ; printf("Result: %g","%1f", $$);}
| LEFTPAR SUB mixed_expression mixed_expression RIGHTPAR { $$ = - ; }
| LEFTPAR MULTIPLY mixed_expression mixed_expression RIGHTPAR {$$ = * ;}
| LEFTPAR DIVIDE mixed_expression mixed_expression RIGHTPAR {$$ = / ;}
| LEFTPAR mixed_expression RIGHTPAR { $$ = ; }
;
%%
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
无论如何,我每隔一段时间就会收到一个解析错误。任何帮助将不胜感激。
要实现这一点:
line: '\n'
| mixed_expression '\n' {printf("\tResult: %f\n", );}
您的词法分析器 return 标记 \n
是必要的。但是你的词法分析器永远不会那样做。事实上,一个换行符在你的词法分析器中不匹配任何规则,所以它会执行default action(见第三段),它只是将不匹配的字符打印到标准输出并继续寻找令牌,不向解析器传递任何内容。
此外,这根本行不通:
| '(stop)\n' {printf("bye!\n"); exit(0); }
因为'(stop)\n'
不是C字符字面量,词法分析器肯定无法return它。我怀疑您会收到来自 lex 的关于此的警告。将符号更改为 "(stop)\n"
将使警告静音,但它仍然不会产生可以从词法分析器 returned 的标记。
还有许多其他问题,包括您使用的语义值标签 (<id>
) 没有出现在您的 %union
声明中,并且您将其声明为未定义的 non-terminal (varName
)。此外,优先级声明 (%left SUB ADD MULTIPLY DIVIDE
) 毫无意义,因为这些标记不会进入 shift-reduce 冲突。
我正在使用 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", );}
| '(stop)\n' {printf("bye!\n"); exit(0); }
;
mixed_expression: DOUBLE {$$ = ;}
| LEFTPAR ADD mixed_expression mixed_expression RIGHTPAR {$$ = + ; printf("Result: %g","%1f", $$);}
| LEFTPAR SUB mixed_expression mixed_expression RIGHTPAR { $$ = - ; }
| LEFTPAR MULTIPLY mixed_expression mixed_expression RIGHTPAR {$$ = * ;}
| LEFTPAR DIVIDE mixed_expression mixed_expression RIGHTPAR {$$ = / ;}
| LEFTPAR mixed_expression RIGHTPAR { $$ = ; }
;
%%
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
无论如何,我每隔一段时间就会收到一个解析错误。任何帮助将不胜感激。
要实现这一点:
line: '\n'
| mixed_expression '\n' {printf("\tResult: %f\n", );}
您的词法分析器 return 标记 \n
是必要的。但是你的词法分析器永远不会那样做。事实上,一个换行符在你的词法分析器中不匹配任何规则,所以它会执行default action(见第三段),它只是将不匹配的字符打印到标准输出并继续寻找令牌,不向解析器传递任何内容。
此外,这根本行不通:
| '(stop)\n' {printf("bye!\n"); exit(0); }
因为'(stop)\n'
不是C字符字面量,词法分析器肯定无法return它。我怀疑您会收到来自 lex 的关于此的警告。将符号更改为 "(stop)\n"
将使警告静音,但它仍然不会产生可以从词法分析器 returned 的标记。
还有许多其他问题,包括您使用的语义值标签 (<id>
) 没有出现在您的 %union
声明中,并且您将其声明为未定义的 non-terminal (varName
)。此外,优先级声明 (%left SUB ADD MULTIPLY DIVIDE
) 毫无意义,因为这些标记不会进入 shift-reduce 冲突。