我正在尝试编写一种可以解析以下 3 个输入的语法
-- testfile --
class hi implements ho:
var x:int;
end;
-- testfile2 --
interface xs:
myFunc(int,int):int
end;
-- testfile3 --
class hi implements ho:
method myMethod(x:int)
return y;
end
end;
这是lexer.l
:
%{
#include <stdio.h>
#include <stdlib.h>
#include "parser.tab.h"
#include <string.h>
int line_number = 0;
void lexerror(char *message);
%}
newline (n|rn)
whitespace [t nr]*
digit [0-9]
alphaChar [a-zA-Z]
alphaNumChar ({digit}|{alphaChar})
hexDigit ({digit}|[A-Fa-f])
decNum {digit}+
hexNum {digit}{hexDigit}*H
identifier {alphaChar}{alphaNumChar}*
number ({hexNum}|{decNum})
comment "/*"[.rn]*"*/"
anything .
%s InComment
%option noyywrap
%%
<INITIAL>{
interface return INTERFACE;
end return END;
class return CLASS;
implements return IMPLEMENTS;
var return VAR;
method return METHOD;
int return INT;
return return RETURN;
if return IF;
then return THEN;
else return ELSE;
while return WHILE;
do return DO;
not return NOT;
and return AND;
new return NEW;
this return THIS;
null return _NULL;
":" return COL;
";" return SCOL;
"(" return BRACL;
")" return BRACR;
"." return DOT;
"," return COMMA;
"=" return ASSIGNMENT;
"+" return PLUS;
"-" return MINUS;
"*" return ASTERISK;
"<" return LT;
{decNum} {
yylval = atoi(yytext);
return DEC;
}
{hexNum} {
const int len = strlen(yytext)-1;
char* substr = (char*) malloc(sizeof(char) * len);
strncpy(substr,yytext,len);
yylval = (int)strtol
( substr
, NULL
, 16);
free (substr);
return HEX;
}
{identifier} {
yylval= (char *) malloc(sizeof(char)*strlen(yytext));
strcpy(yylval, yytext);
return ID;
}
{whitespace} {}
"/*" BEGIN InComment;
}
{newline} line_number++;
<InComment>{
"*/" BEGIN INITIAL;
{anything} {}
}
. lexerror("Illegal input");
%%
void lexerror(char *message)
{
fprintf(stderr,"Error: "%s" in line %d. = %sn",
message,line_number,yytext);
exit(1);
}
这是parser.y
:
%{
# include <stdio.h>
int yylex(void);
void yyerror(char *);
extern int line_number;
%}
%start Program
%token INTERFACE END CLASS IMPLEMENTS VAR METHOD INT RETURN IF THEN ELSE
%token WHILE DO NOT AND NEW THIS _NULL EOC SCOL COL BRACL BRACR DOT COMMA
%token ASSIGNMENT PLUS ASTERISK MINUS LT EQ DEC HEX ID NEWLINE
%%
Program: INTERFACE Interface SCOL { printf("interfacen"); }
| CLASS Class SCOL { printf("classn");}
| error { printf("error on: %sn", $$); }
;
Interface: ID COL
AbstractMethod
END
;
AbstractMethod: ID BRACL Types BRACR COL Type
;
Types : Type COMMA Types
| Type
;
Class: ID
IMPLEMENTS ID COL
Member SCOL
END
;
Member: VAR ID COL Type
| METHOD ID BRACL Pars BRACR Stats END
;
Type: INT
| ID
;
Pars: Par COMMA Pars
| Par
;
Par: ID COL Type
;
Stats: Stat SCOL Stat
| Stat
;
Stat: RETURN Expr
| IF Expr THEN Stats MaybeElse END
| WHILE Expr DO Stats END
| VAR ID COL Type COL ASSIGNMENT Expr
| ID COL ASSIGNMENT Expr
| Expr
;
MaybeElse :
| ELSE Stats
;
Expr: NOT Term
| NEW ID
| Term PLUS Term
| Term ASTERISK Term
| Term AND Term
| Term ArithOp Term
| Term
;
ArithOp: MINUS
| LT
| ASSIGNMENT
;
Term: BRACL Expr BRACR
| Num
| THIS
| ID
| Term DOT ID BRACL Exprs BRACR
| error { printf("error in term: %sn", $$); }
;
Num : HEX
| INT
;
Exprs : Expr COMMA Exprs
| Expr
;
%%
void yyerror(char *s) {
fprintf(stderr, "Parse Error on line %i: %sn", line_number, s);
}
int main(void){
yyparse();
}
前两个输入按预期识别,
但是,第三个失败并出现错误error on: y
,我不知道为什么。
在我看来,这应该是一个Class
,其Member
METHOD
包含一个Stat
(ement)RETURN
,Expr
Term
是一个ID
。
我尝试评论并删除所有不必要的位,但结果仍然相同。 我还查看了解析器以验证我的标识符是否正确解析,但在我看来,它们应该解析。
为什么这里不承认return y
y
? 我不知道语法中是否存在冲突?
(请注意,我不希望您修复完整的语法;我只是在问这不起作用的原因。我确定那里还有其他错误,但我真的无法修复这个错误。
这也是我的制作文件:
CC = gcc
LEX = flex
YAC = bison
scanner: parser.y lexer.l
$(YAC) -d -Wcounterexamples parser.y
$(LEX) lexer.l
$(CC) parser.tab.c parser.tab.h lex.yy.c -o parser
clean:
rm -f *.tab.h *.tab.c *.gch *.yy.c
rm ./parser
测试:
cat testfile3 | ./parser
首先,你的语法中有一个错误:
Stats: Stat SCOL Stat
| Stat
;
必须是
Stats: Stat SCOL Stats
| Stat
;
(行尾添加"s")
其次,您在testfile3中的定义不遵循您的语法,并且必须
class hi implements ho:
method myMethod(x:int)
return y
end;
end;
所以return y
后面的';"必须在第一个end
之后移动
(return x
似乎更合乎逻辑,但这是另一个主题,您不检查ID的有效性)
其中,一个类只能有一个成员,这是非常有限/限制性的