我最近开始学习基本的Flex和Bison,因为我必须为简单(但不是太简单)的语法编写解析器。我决定在我的语法中使用简化的Java语言。我创建了.l
和.y
文件,所有内容都编译而没有错误(我正在使用gcc进行编译)。
问题是,每次运行生成的程序时,我都会获得Syntax Error
,即使是简单的输入,例如:private class Something{}
。我没有得到Syntax Error
的唯一一次是当我输入一个空行(\n
)时。
我几天来一直在努力解决这个问题,我怀疑我的语法中存在某个问题,但我似乎无法找到它。当然也可能存在其他问题,因为我对Flex和Bison很新。
任何帮助都会非常感激。
以下是.l
和.y
个文件:
java.l
%{
#include "java.tab.h"
%}
%option noyywrap
%%
"\n" return 0;
[ \t] ;
"private" {return PRIVATE;}
"public" {return PUBLIC;}
"protected" {return PROTECTED;}
"implenets" {return IMPLEMENTS;}
"extends" {return EXTENDS;}
"class" {return CLASS;}
"interface" {return INTERFACE;}
"if" {return IF;}
"while" {return WHILE;}
"return" {return RETURN;}
"true" {return BOOLEAN;}
"false" {return BOOLEAN;}
[A-z][a-z0-9]* {return NAME;}
"\""[A-z0-9]*"\"" {return STRING;}
"-"?[1-9][0-9]* {return INT;}
"+"|"-"|"*"|"/"|"="|"==" {return OPERATOR;}
%%
java.y
%{
#include <stdio.h>
int cond=0;
int loops=0;
int assigns=0;
int funcs=0;
int classes=0;
void yyerror(const char* msg){printf("Error: %s\n", msg);}
%}
%token PUBLIC
%token PRIVATE
%token PROTECTED
%token NAME
%token IMPLEMENTS
%token EXTENDS
%token CLASS
%token INTERFACE
%token IF
%token WHILE
%token STRING
%token BOOLEAN
%token OPERATOR
%token RETURN
%token INT
%%
Code: Class Code | /*empty*/ {printf("classes: %d\n", classes); printf("functions: %d\n", funcs); printf("conditions: %d\n", cond);
printf("loops: %d\n", loops); printf("assign operations: %d\n", assigns);} ;
Class: Modifier ClassType NAME Extra '{' Functions '}' ;
Modifier: PUBLIC | PRIVATE | PROTECTED ;
ClassType: CLASS | INTERFACE ;
Extra: IMPLEMENTS NAME | EXTENDS NAME | /*empty*/ ;
Functions: Function Functions | /*empty*/ ;
Function: Type NAME '(' Arguments ')' '{' Commands '}' {funcs++;} ;
Arguments: Argument Arguments | /*empty*/ ;
Argument: Type NAME Separator ;
Type: STRING | INT | BOOLEAN ;
Separator: ',' | /*empty*/ ;
Commands: Command Commands | /*empty*/ ;
Command: Condition | Loop | Assignment | Return ;
Condition: IF '(' Comparison ')' '{' Commands '}' {cond++;} ;
Loop: WHILE '(' Comparison ')' '{' Commands '}' {loops++;} ;
Comparison: NAME OPERATOR INT | NAME OPERATOR NAME | INT OPERATOR NAME ;
Assignment: NAME '=' Type ';' {assigns++;} ;
Return: RETURN RetVal ';' ;
RetVal: NAME | Type ;
%%
int main()
{
yyparse();
return 0;
}
答案 0 :(得分:2)
这是一个开始:
首先,flex
提供的默认规则只是回应任何其他规则不匹配的字符。 {
和}
与任何规则都不匹配,因此它们将被回应并且永远不会被野牛看到,这使得生产Class
无法匹配。一个简单的解决方案是将默认规则作为最后一个flex
规则:
. { return yytext[0]; }
其次,[A-z]
与[A-Za-z]
不同,因为Z
和a
在ASCII中不连续。我建议将[[:alpha:]]
用于字母字符,将[[:alnum:]]
用于字母数字,但[A-Za-z]
和[A-Za-z0-9]
没有任何问题。在这两种情况下,您可能希望允许其他字符,例如_
。 (这不会给你造成任何直接问题,只是一个注释。)
第三,你错误地拼写了"implements"
。
答案 1 :(得分:0)
对于一般的解析器调试,您可能会发现使用java.tab.c
编译解析器(-DYYDEBUG
文件)并将行yydebug=1;
粘贴到main
函数中之前很有用致电yyparse
。
这将导致解析器打印它读取的所有令牌以及它所执行的操作,允许您查看它正在做什么并且通常显示正在发生的事情以及为什么您会为您认为的输入获得意外的语法错误是对的。