这是我的lex和yacc文件,用于识别回文字符串,但它为有效字符串和无效字符串提供“INVALID”。请帮我找到问题,我是lex和yacc的新手。 Thanx提前
LEX文件
%{
#include "y.tab.h"
%}
%%
a return A;
b return B;
. return *yytext;
%%
YACC文件
%{
#include<stdio.h>
#include "lex.yy.c"
int i=0;
%}
%token A B
%%
S: pal '\n' {i=1;}
pal:
| A pal A {printf("my3");i=1;}
| B pal B {printf("my4");i=1;}
| A {printf("my1");i=1;}
| B {printf("my2");i=1;}
;
%%
int main()
{
printf("Enter Valid string\n");
yyparse();
if(i==1)
printf("Valid");
return 0;
}
int yyerror(char* s)
{
printf("Invalid\n");
return 0;
}
示例:输入的字符串是:aba 预期输出应为有效,但它给出了无效
答案 0 :(得分:0)
用Yacc解决这个问题是不可能的。
Yacc是LALR(1)解析器生成器。 LALR指的是一类语法。语法是推理解析的数学工具。一个parens指的是前瞻 - 这是我们在确定要遵循哪些替代产品(或“规则”)之前考虑的最大令牌数量。请记住,解析算法是一次通过,它不能回溯并尝试另一种替代方法,就像一些正则表达式引擎那样。
关于你的palindrom问题,当解析器遇到'a'时,它必须以某种方式选择正确的选择
朋友: - 'a'本身就是一个有效的回文,我们称之为内核
朋友:[A]朋友 - 外层,增加筑巢水平
朋友:朋友[A] - 外层,降低筑巢水平
如果没有无限的前瞻,做出正确的选择是不可能的,但是Yacc只有一个前瞻性的标记。
Yacc处理这种语法的方式也很有趣。
如果语法不明确或不符合LR(1),则生成的堆栈自动机是非确定性的。有一些内置工具可以解决它。
第一个工具是优先级和关联性,用于处理编程语言中的运算符(此处不相关)。
另一个是怪癖 - 默认情况下,Yacc更喜欢“转变”为“减少”。这两个是针对解析算法的内部操作的技术性问题。基本上,令牌会“转移”到堆栈中。一旦顶部的一组令牌与规则匹配,就可以“减少”它们,用规则左侧的单个非终端替换整个组。
因此,一旦我们在顶部有'a',我们可以将它减少到朋友,或者我们可以在假设最终会出现嵌套的朋友时转移另一个令牌。 Yacc更喜欢后者。
这种偏好的原因是什么?大多数语言中if-then-else语句都存在同样的含糊之处。考虑两个嵌套的if语句,但只考虑一个else子句。 Yacc将其他内容附加到最内层的if语句中,这样做是正确的。
除了Yacc可以生成一个报告,突出显示语法中的问题,如上面提到的shift-reduce冲突。
答案 1 :(得分:0)
在@ChrisDod和@NickZavaritsky评论的延续中,我添加了一个glr(bison)解析器的工作版本。
%option noyywrap
%%
a return A;
b return B;
\n return '\n';
. {fprintf(stderr, "Error\n"); exit(1);}
%%
和Yacc / bison
%{
#include <stdio.h>
int i=0;
%}
%token A B
%glr-parser
%%
S : pal '\n' {i=1; return 1 ;}
| error '\n' {i=0; return 1 ;}
pal: A pal A
| B pal B
| A
| B
|
;
%%
#include "lex.yy.c"
int main() {
yyparse();
if(i==1) printf("Valid\n");
else printf("inValid\n");
return 0;
}
int yyerror(char* s) { return 0; }
词法分析器中引入了一些变化:(1)\n
缺失; (2)未知的字符现在是致命的错误;
错误恢复error
用于获取“无效回文”情况。