编辑#1:我认为问题出在我的.l文件中。我不认为规则被视为规则,我不知道如何将规则的终端视为字符串。
我编译器类的最后一个项目是为简单的SQL语法编写.l和.y文件。我没有使用Flex或Yacc的经验,所以我写的所有内容都拼凑在一起。我只对这些文件的工作方式有基本的了解,所以如果你发现我的问题,你还可以解释一下该文件的哪一部分应该做什么?我甚至不确定'%'符号是做什么的。
基本上,当我尝试解析某些内容时,某些规则不起作用。一些规则挂起,其他规则在他们应该接受时拒绝。我需要实现以下语法:
start
::= expression
expression
::= one-relation-expression | two-relation-expression
one-relation-expression
::= renaming | restriction | projection
renaming
::= term RENAME attribute AS attribute
term
::= relation | ( expression )
restriction
::= term WHERE comparison
projection
::= term | term [ attribute-commalist ]
attribute-commalist
::= attribute | attribute , attribute-commalist
two-relation-expression
::= projection binary-operation expression
binary-operation
::= UNION | INTERSECT | MINUS | TIMES | JOIN | DIVIDEBY
comparison
::= attribute compare number
compare
::= < | > | <= | >= | = | <>
number
::= val | val number
val
::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
attribute
::= CNO | CITY | CNAME | SNO | PNO | TQTY |
SNAME | QUOTA | PNAME | COST | AVQTY |
S# | STATUS | P# | COLOR | WEIGHT | QTY
relation
::= S | P | SP | PRDCT | CUST | ORDERS
这是我的.l文件:
%{
#include <stdio.h>
#include "p5.tab.h"
%}
binaryOperation UINION|INTERSECT|MINUS|TIMES|JOIN|DIVIDEBY
compare <|>|<=|>=|=|<>
attribute CNO|CITY|CNAME|SNO|PNO|TQTY|SNAME|QUOTA|PNAME|COST|AVQTY|S#|STATUS|P#|COLOR|WEIGHT|QTY
relation S|P|SP|PRDCT|CUST|ORDERS
%%
[ \t\n]+ ;
{binaryOperation} return binaryOperation;
{compare} return compare;
[0-9]+ return val;
{attribute} return attribute;
{relation} return relation;
"RENAME" return RENAME;
"AS" return AS;
"WHERE" return WHERE;
"(" return '(';
")" return ')';
"[" return '[';
"]" return ']';
"," return ',';
. {printf("REJECT\n");
exit(0);}
%%
这是我的.y文件:
%{
#include <stdio.h>
#include <stdlib.h>
%}
%token RENAME attribute AS relation WHERE binaryOperation compare val
%%
start:
expression {printf("ACCEPT\n");}
;
expression:
oneRelationExpression
| twoRelationExpression
;
oneRelationExpression:
renaming
| restriction
| projection
;
renaming:
term RENAME attribute AS attribute
;
term:
relation
| '(' expression ')'
;
restriction:
term WHERE comparison
;
projection:
term
| term '[' attributeCommalist ']'
;
attributeCommalist:
attribute
| attribute ',' attributeCommalist
;
twoRelationExpression:
projection binaryOperation expression
;
comparison:
attribute compare number
;
number:
val
| val number
;
%%
yyerror() {
printf("REJECT\n");
exit(0);
}
main() {
yyparse();
}
yywrap() {}
这是我的makefile:
p5: p5.tab.c lex.yy.c
cc -o p5 p5.tab.c lex.yy.c
p5.tab.c: p5.y
bison -d p5.y
lex.yy.c: p5.l
flex p5.l
这有效:
重新命名CNO作为城市
这些不是:
取值
何时CNO = 5
我没有测试过所有内容,但我认为这些问题存在一个共同的问题。
答案 0 :(得分:1)
你的语法是正确的,问题是你是以交互方式运行的。当你调用yyparse()时,它将尝试读取所有输入。因为输入
取值
后面可以是RENAME或者它不会接受的地方。类似地,
何时CNO = 5
后面可以跟一个或多个数字,因此yyparse在获得EOF或意外令牌之前不会接受。
您要做的是遵循建议here并更改p5.l以获得这些内容:
[ \t]+ ;
\n if (yyin==stdin) return 0;
这样,当您以交互方式运行时,将使用ENTER键作为输入的结束。
此外,您希望将left recursion用于数字:
number:
val
| number val
;