2013-11-02 111 views
4

我想写这将是能够消耗下面输入语法:的Flex /野牛语法错误

begin #this is a example 
    x = 56; 

    while x > 0 do 
    begin 
    point 15.6 78.96; 
    end; 
end; 

这里是lexer.l文件:

%option noyywrap 

%{ 
#include "parser.h" 
#include <stdlib.h> 
#include <stdio.h> 
const char * const unrecognizedToken = "Unrecognized token"; 

%} 


NewLine     \n 
WhiteSpaces    [\r\t\f\v ]+ 
Semicolon     ; 

digit  [0-9] 
number1  {digit}+\.?([eE][-+]?{digit}+)? 
number2  {digit}*\.{digit}+([eE][-+]?{digit}+)? 
double_number  {number1}|{number2} 

BEGIN     "begin" 
END      "end" 
WHILE     "while" 
DO      "do" 
POINT     "point" 

%x POINT_DEFINITIONS 

%% 

{WhiteSpaces} { 
    printf("WhiteSpaces"); 
    printf("\n"); 
} 

{NewLine}  { 
    printf("NewLine"); 
    printf("\n"); 
} 


{WHILE} { 
    printf("While"); 
    printf("\n"); 
    return TOKEN_WHILE; 
} 

{BEGIN} { 
    printf("TOKEN_BEGIN"); 
    printf("\n"); 
    return TOKEN_BEGIN; 
} 

{END} { 
    printf("TOKEN_END"); 
    printf("\n"); 
    return TOKEN_END; 
} 

{DO} { 
    printf("DO"); 
    printf("\n"); 
    return TOKEN_DO; 
} 

{POINT}         { 
    printf("POINT_START"); 
    printf("\n"); 
    BEGIN POINT_DEFINITIONS; 
    return TOKEN_POINT; 
} 

<POINT_DEFINITIONS>{double_number}    { 
    printf("POINT_DEFINITIONS %s", yytext); 
    printf("\n"); 
    yylval.dval = atof(yytext); 
    return TOKEN_DOUBLE; 
} 

<POINT_DEFINITIONS>{WhiteSpaces}    { 
    printf("WhiteSpaces"); 
    printf("\n"); 
} 

[a-zA-Z_][a-zA-Z0-9_]* { 
    printf("TOKEN_IDENTIFIER"); 
    printf("\n"); 
    yylval.name = strdup(yytext); 
    return TOKEN_IDENTIFIER; 
} 

[()=;] { 
    printf("yytext = %s", yytext); 
    printf("\n"); 
    return *yytext; 
} 

[*/+\-<>] { 
    printf("TOKEN_OPERATOR"); 
    printf("\n"); 
    yylval.op = *yytext; 
    return TOKEN_OPERATOR; 
} 

[-]?[0-9]+ { 
    printf("TOKEN_VALUE"); 
    printf("\n"); 
    yylval.val = atoi(yytext); 
    return TOKEN_VALUE; 
} 

#.*   { 
    printf("COMMENT"); 
    printf("\n"); 
    /*comment*/ 
} 

.   { printf("%s", unrecognizedToken); } 

这里是该parser.y文件:

%error-verbose 
%{ 
#define YYDEBUG 1 
%} 

%union { 
    int val; 
    double dval; 
    char op; 
    char* name; 
} 

%token TOKEN_BEGIN TOKEN_END TOKEN_WHILE TOKEN_DO TOKEN_POINT TOKEN_OPERATOR TOKEN_VALUE TOKEN_IDENTIFIER TOKEN_DOUBLE 
%start program 

%{ 
void yyerror(const char* const message); 

%} 

%% 

program: statement';'; 

block: TOKEN_BEGIN statements TOKEN_END { printf("rule block\n"); }; 

statements: 
     statement';' statements { printf("rule statements\n"); } 
    |; 

statement: 
    | assignment 
    | command 
    | whileStmt 
    | block; 

assignment: TOKEN_IDENTIFIER '=' TOKEN_VALUE { 
    printf("rule Assignment\n"); 
} ; 

whileStmt: TOKEN_WHILE condition TOKEN_DO block {printf("rule While\n");}; 

condition: TOKEN_IDENTIFIER { printf("rule token_identifier\n"); } 
    | TOKEN_VALUE { printf("rule token_value\n"); } 
    | condition TOKEN_OPERATOR condition { printf("rule condition TOKEN_OPERATOR condition\n"); }; 

command: TOKEN_POINT TOKEN_DOUBLE TOKEN_DOUBLE { printf("rule Command\n"); }; 

%% 

#include <stdlib.h> 

void yyerror(const char* const message) 
{ 
    printf("Parse error:%s\n", message); 
    exit(1); 
} 

int main() 
{ 
    yyparse(); 
} 

,但我得到以下错误信息:

Parse error:syntax error, unexpected $end, expecting ';' 

编译如下:

flex -o lexer.c lexer.l 
bison -v -d -o parser.c parser.y 
gcc parser.c lexer.c -o parser -g -DYYDEBUG=1 

要运行解析器:

./parser < example 

能否请你帮我找到了什么问题? 为什么语法不能接受上面的例子作为输入?

+1

+1了通过示例输入,实际输出(错误消息)和完整的代码很好地解决了问题。 (我假设它是完整的;它看起来完整,但我还没有尝试编译它。) –

回答

2

你的问题出现在你的词法分析器中(不管你的语法是否存在问题 - 我没有分析过这个语法,因为我首先在词法分析器中遇到了问题,而且足以防止语法加工)。

我添加了一个测试main()lexer.l

%% 

YYSTYPE yylval; 

int main(void) 
{ 
    int token; 
    while ((token = yylex()) != 0) 
     printf("Token: %d (%s)\n", token, yytext); 
    return 0; 
} 

我然后跑它在你的示例代码,看看标流是否正确产生。我得到的输出是:

TOKEN_BEGIN 
Token: 258 (begin) 
WhiteSpaces 
COMMENT 
NewLine 
WhiteSpaces 
TOKEN_IDENTIFIER 
Token: 265 (x) 
WhiteSpaces 
yytext = = 
Token: 61 (=) 
WhiteSpaces 
TOKEN_VALUE 
Token: 264 (56) 
yytext = ; 
Token: 59 (;) 
NewLine 
NewLine 
WhiteSpaces 
While 
Token: 260 (while) 
WhiteSpaces 
TOKEN_IDENTIFIER 
Token: 265 (x) 
WhiteSpaces 
TOKEN_OPERATOR 
Token: 263 (>) 
WhiteSpaces 
TOKEN_VALUE 
Token: 264 (0) 
WhiteSpaces 
DO 
Token: 261 (do) 
NewLine 
WhiteSpaces 
TOKEN_BEGIN 
Token: 258 (begin) 
NewLine 
WhiteSpaces 
POINT_START 
Token: 262 (point) 
WhiteSpaces 
POINT_DEFINITIONS 15.6 
Token: 266 (15.6) 
WhiteSpaces 
POINT_DEFINITIONS 78.96 
Token: 266 (78.96) 
; 
WhiteSpaces 
end; 
end; 

正如你所看到的,返回到主程序的最后一个标记是78.96。

当你识别一个POINT时,你开始POINT_DEFINITIONS状态。然而,一旦在那个状态下,你永远处于这个状态;你永远不会回到INITIAL状态。你可能需要添加一个规则到POINT_DEFINITIONS开始识别分号并执行BEGIN INITIAL;状态:

<POINT_DEFINITIONS>{Semicolon} { 
    printf("Semicolon in POINT_DEFINITION state\n"); 
    BEGIN INITIAL; 
    return *yytext; 
} 

有了这个到位,输出的末尾是:

... 
TOKEN_BEGIN 
Token: 258 (begin) 
NewLine 
WhiteSpaces 
POINT_START 
Token: 262 (point) 
WhiteSpaces 
POINT_DEFINITIONS 15.6 
Token: 266 (15.6) 
WhiteSpaces 
POINT_DEFINITIONS 78.96 
Token: 266 (78.96) 
Semicolon in POINT_DEFINITION state 
Token: 59 (;) 
NewLine 
WhiteSpaces 
TOKEN_END 
Token: 259 (end) 
punctuation: yytext = ; 
Token: 59 (;) 
NewLine 
TOKEN_END 
Token: 259 (end) 
punctuation: yytext = ; 
Token: 59 (;) 
NewLine 
+0

[Jonathan Leffler](http://stackoverflow.com/users/15168/jonathan-leffler)感谢您的答案。你能指出语法方面有什么问题吗? –

+1

我编译语法得到'parser.h'。有一个转变/减少冲突。我从来没有将词法分析器与语法结合起来,因为我的第一个检查(词法分析器是否行为不端)是正确的开始。由于语法从来没有收到词法分析器的最后五个令牌(分号,结束,分号,结尾,分号),所以当它得到EOF并且缺少这五个时,它并不奇怪。 IOW,只要移位/减少冲突得到正确处理,我就没有理由认为语法中存在问题。我已经澄清了我的回答。 –