Flex和Yacc语法问题

时间:2016-04-23 19:32:47

标签: parsing flex-lexer yacc

编辑#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

我没有测试过所有内容,但我认为这些问题存在一个共同的问题。

1 个答案:

答案 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
    ;