Parsing 解析使用二进制运算符的表达式时出现Yacc和Lex错误

Parsing 解析使用二进制运算符的表达式时出现Yacc和Lex错误,parsing,yacc,lex,lexical-analysis,Parsing,Yacc,Lex,Lexical Analysis,我不熟悉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

我不熟悉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();
}
尝试在命令行上输入算术表达式进行求值时,会导致以下错误:

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

您的lexer缺少匹配和返回标记的规则,例如
'+'
'*'
,因此如果您的输入中有任何标记,它将只回显并丢弃它们。这就是当您输入
fd(10+10)
时所发生的情况——lexer返回标记
fd
NUMBER
NUMBER
,而
+
返回到stdout。然后解析器给出一个语法错误

您希望添加一条规则以返回这些单字符标记。最简单的方法是在结尾处向.l文件添加一条规则:

.               { return *yytext; }
它匹配任何单个字符

请注意,这与
\n
(换行符)不匹配,因此输入中的换行符仍将被回显和忽略。您可能希望将它们(以及制表符和回车符)添加到跳过空格规则中:

[ \t\r\n]       { /* skip blanks */ }

谢谢,我想知道这一点。我想出于某种原因,因为引用了
+
等,它们在yacc中是某种特殊的“基本”运算符。它们是,在yacc中。这就是为什么只返回char值有效,而不必为它们定义%标记。但它们在lex/flex中并不特殊。我明白了,为了让它们正确地说,它们首先需要在Lex中定义为标记
bk 10
将首先显示
expression->number
,并且似乎没有捕捉到
bk
。但是,再次输入它,它将正确解析,即
语句->bk expr
,然后是
expression->number
。延迟的原因是什么?@Dylan:那是因为你的printf在e动作,当规则减少时发生——当规则的rhs上的所有符号都被解析,并且它们被组合成lhs上的单个符号时。解析从标记到符号,但是使用规则的
->
会让你陷入相反的思考方向。
[ \t\r\n]       { /* skip blanks */ }