我正在尝试使用lex和yacc并遇到一个奇怪的问题,但我认为最好在详细说明问题之前向我们展示我的代码。这是我的词法分析员:
%{
#include <stdlib.h>
#include <string.h>
#include "y.tab.h"
void yyerror(char *);
%}
%%
[a-zA-Z]+ {
yylval.strV = yytext;
return ID;
}
[0-9]+ {
yylval.intV = atoi(yytext);
return INTEGER;
}
[\n] { return *yytext; }
[ \t] ;
. yyerror("invalid character");
%%
int yywrap(void) {
return 1;
}
这是我的解析器:
%{
#include <stdio.h>
int yydebug=1;
void prompt();
void yyerror(char *);
int yylex(void);
%}
%union {
int intV;
char *strV;
}
%token INTEGER ID
%%
program: program statement EOF { prompt(); }
| program EOF { prompt(); }
| { prompt(); }
;
args: /* empty */
| args ID { printf(":%s ", $<strV>2); }
;
statement: ID args { printf("%s", $<strV>1); }
| INTEGER { printf("%d", $<intV>1); }
;
EOF: '\n'
%%
void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
}
void prompt() {
printf("> ");
}
int main(void) {
yyparse();
return 0;
}
一种非常简单的语言,由不超过字符串和整数以及基本REPL组成。现在,您将在解析器中注意到 args 是使用前导冒号输出的,目的是当与语句的规则的第一个模式结合时与REPL的交互看起来像这样:
> aaa aa a
:aa :a aaa>
然而,互动是这样的:
> aaa aa a
:aa :a aaa aa aa
>
为什么以下规则中的令牌ID
statement: ID args { printf("%s", $<strV>1); }
| INTEGER { printf("%d", $<intV>1); }
;
是否包含总输入字符串的语义值,包括换行符?我的语法如何重新编写,以便我打算进行交互?
答案 0 :(得分:2)
如果您希望令牌字符串保持有效,则必须在读取时将其保留。我将statement
规则修改为:
statement: ID { printf("<%s> ", $<strV>1); } args { printf("%s", $<strV>1); }
| INTEGER { printf("%d", $<intV>1); }
;
然后,根据您的输入,我得到输出:
> aaa aa a
<aaa> :aa :a aaa aa a
>
请注意,在读取初始ID时,令牌正是您所期望的。但是,由于您没有保留令牌,因此在解析args
之后返回打印时,字符串已被修改。
答案 1 :(得分:0)
我认为args和语句产生之间存在关联性冲突。这由bison -v
parser.output文件的(部分)输出证实:
Nonterminals, with rules where they appear
$accept (6)
on left: 0
program (7)
on left: 1 2 3, on right: 0 1 2
statement (8)
on left: 4 5, on right: 1
args (9)
on left: 6 7, on right: 4 7
EOF (10)
on left: 8, on right: 1 2
事实上,我很难弄清楚你的语法试图接受什么。作为旁注,我可能会将您的EOF作品作为EOL令牌移动到词法分析器中;这将使解析错误的重新同步变得更容易。
更好地解释你的意图会有所帮助。