我是Lex和Yacc的新手,我正在尝试为一种简单的语言创建一个解析器,它允许基本的算术和等式表达式。虽然我有一些工作,但我在尝试解析涉及二进制操作的表达式时遇到错误。这是我的.y
文件:
%{
#include <stdlib.h>
#include <stdio.h>
%}
%token NUMBER
%token HOME
%token PU
%token PD
%token FD
%token BK
%token RT
%token LT
%left '+' '-'
%left '=' '<' '>'
%nonassoc UMINUS
%%
S : statement S { printf("S -> stmt S\n"); }
| { printf("S -> \n"); }
;
statement : HOME { printf("stmt -> HOME\n"); }
| PD { printf("stmt -> PD\n"); }
| PU { printf("stmt -> PU\n"); }
| FD expression { printf("stmt -> FD expr\n"); }
| BK expression { printf("stmt -> BK expr\n"); }
| RT expression { printf("stmt -> RT expr\n"); }
| LT expression { printf("stmt -> LT expr\n"); }
;
expression : expression '+' expression { printf("expr -> expr + expr\n"); }
| expression '-' expression { printf("expr -> expr - expr\n"); }
| expression '>' expression { printf("expr -> expr > expr\n"); }
| expression '<' expression { printf("expr -> expr < expr\n"); }
| expression '=' expression { printf("expr -> expr = expr\n"); }
| '(' expression ')' { printf("expr -> (expr)\n"); }
| '-' expression %prec UMINUS { printf("expr -> -expr\n"); }
| NUMBER { printf("expr -> number\n"); }
;
%%
int yyerror(char *s)
{
fprintf (stderr, "%s\n", s);
return 0;
}
int main()
{
yyparse();
}
这是Lex的.l
文件:
%{
#include "testYacc.h"
%}
number [0-9]+
%%
[ ] { /* skip blanks */ }
{number} { sscanf(yytext, "%d", &yylval); return NUMBER; }
home { return HOME; }
pu { return PU; }
pd { return PD; }
fd { return FD; }
bk { return BK; }
rt { return RT; }
lt { return LT; }
%%
当我尝试在命令行上输入算术表达式以进行评估时,会导致以下错误:
home
stmt -> HOME
pu
stmt -> PU
fd 10
expr -> number
fd 10
stmt -> FD expr
expr -> number
fd (10 + 10)
stmt -> FD expr
(expr -> number
+stmt -> FD expr
S ->
S -> stmt S
S -> stmt S
S -> stmt S
S -> stmt S
S -> stmt S
syntax error
答案 0 :(得分:2)
你的词法分析器缺少匹配和返回标记的规则,例如'+'
和'*'
,所以如果输入中有任何内容,它只会回显它们并丢弃它们。当您输入fd (10 + 10)
时会发生这种情况 - 词法分析器返回标记FD
NUMBER
NUMBER
,而+
和(
会回显到标准输出。解析器然后给出语法错误。
您想要添加规则以返回这些单个字符标记。最简单的方法是在最后添加一个规则到.l文件中:
. { return *yytext; }
匹配任何单个字符。
请注意,这与\n
(换行符)不匹配,因此输入中的换行符仍会被回显和忽略。您可能希望将它们(以及制表符和回车符)添加到跳过空白规则:
[ \t\r\n] { /* skip blanks */ }