我正在用简单的C编写一个编译器的解析器,我试图理解为什么我有 yacc:22次/减少冲突,15次减少/减少冲突。
lex文件
letter [a-zA-Z]
Hexdigits [A-F|0-9]
OctalDigit [0-7]
digit [0-9]
digitMZ [1-9]
newline (\n)
integerNum "0"|{digitMZ}{digit}*
HexNumber ("0X"|"0x"){Hexdigits}+
OctalNumber ["0"]{OctalDigit}+
BinaryNumber ["0"|"1"]+"b"
identifier {letter}({letter}|{digit}|"_")*
char "'"."'"
wordString \"[^\"]*\"
Comment "/%"[^"%/"]+"%/"
StrDec "["{integerNum}"]"
%{
%}
%option yylineno
%%
"string"" "*{StrDec} { return STRING_DECLERATION;}
boolean { return BOOLEAN; }
else { return ELSE; }
if { return IF; }
integer { return INTEGER; }
procedure { return PROCEDURE; }
char { return CHAR; }
string { return STRING; }
var { return VAR; }
intptr { return INTPTR; }
charptr { return CHARPTR; }
return { return RETURN; }
void { return VOID; }
while { return WHILE; }
"isprint()" { return IS_PRINT; }
true|false { return BOOLCONSTANT; }
":" { return COLON; }
"+" { return PLUS; }
"&" { return ADDRESS; }
"^" { return DEREFERENCE; }
"-" { return MINUS; }
"*" { return MULTIPLICATION; }
"&&" { return AND; }
"/" { return DIVISION; }
"<=" { return LESSEQUAL; }
"<" { return LESS; }
">" { return GREATER; }
">=" { return GREATEREQUAL; }
"==" { return EQUAL; }
"!=" { return NOTEQUAL; }
"=" { return ASSIGN; }
";" { return SEMICOLON; }
"," { return COMMA; }
"(" { return LEFTPAREN; }
")" { return RIGHTPAREN; }
"[" { return LEFTBRACKET; }
"]" { return RIGHTBRACKET; }
"{" { return LEFTBRACE; }
"}" { return RIGHTBRACE; }
"||" { return OR; }
"!" { return NOT; }
" "+ { }
"|" {return ABS_LENGTH;}
" "+ {}
{newline} { }
{Comment} {}
{wordString} {return WORDSTRING; }
{integerNum} {return INTEGER_CONST; }
{char} {return CHAR_IDENTIFIER; }
{identifier} {return IDENTIFIER; }
{HexNumber} {return HEX_NUMBER; }
{OctalNumber} {return OCTAL_NUMBER; }
{BinaryNumber} {return BINARY_NUMBER; }
. {return ERROR; }
%%
yacc文件
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define YYDEBUG 1
#define YYSTYPE struct node*
int yyerror(char*);
int yylex();
typedef struct node
{
char * rtoken;
struct node * left;
struct node * right;
char * ltoken;
}node;
node * mknode(char * ltoken, node * left, node * right,char * rtoken);
void printtree(node * tree);
char * getLT(node *);
extern char *yytext;
%}
%token STRING_DECLERATION
%token STRING
%token WORDSTRING
%token BOOLEAN
%token BREAK
%token ELSE
%token IF
%token IMPLEMENTS
%token INTEGER
%token PROCEDURE
%token CHAR
%token VAR
%token INTPTR
%token CHARPTR
%token RETURN
%token VOID
%token WHILE
%token IS_PRINT
%token BOOLCONSTANT
%token PLUS
%token COLON
%token ADDRESS
%token DEREFERENCE
%token MINUS
%token MULTIPLICATION
%token AND
%token DIVISION
%token LESS
%token LESSEQUAL
%token GREATER
%token GREATEREQUAL
%token EQUAL
%token NOTEQUAL
%token ASSIGN
%token SEMICOLON
%token COMMA
%token LEFTPAREN
%token RIGHTPAREN
%token LEFTBRACKET
%token RIGHTBRACKET
%token LEFTBRACE
%token RIGHTBRACE
%token OR
%token NOT
%token ABS_LENGTH
%token CHAR_IDENTIFIER
%token HEX_NUMBER
%token OCTAL_NUMBER
%token BINARY_NUMBER
%token ERROR
%token INTEGER_CONST
%token IDENTIFIER
%%
start: s{printtree($1);}
;
s: expr {$$=$1;}
|expr s {node *yu = mknode("",$1,NULL,"\n");$$= mknode("",yu,$2,"");}
;
expr: function {$$=$1;}
|assignment SEMICOLON {$$=$1;}
|decleration SEMICOLON {$$=$1;}
|condition {$$=$1;}
|BRACES {$$=$1;}
;
function: PROCEDURE iden LEFTPAREN argListOpt RIGHTPAREN RETURN identifiertype compondStmt
{node *z =mknode("RETURN:",$7,NULL,"\n");node *o =mknode(getLT($2),$4,z,""); $$ = mknode("(PROCEDURE",o,$8,"\n)\n");}
|PROCEDURE iden LEFTPAREN RIGHTPAREN RETURN identifiertype compondStmt
{node *z2 = mknode("",NULL,NULL,"");node *z1 =mknode("RETURN:",$6,NULL,"\n");
node *o =mknode(getLT($2),z2,z1,""); $$ = mknode("(PROCEDURE",o,$7,"\n)\n");}
;
argListOpt: multidentifier COLON identifiertype SEMICOLON argListOpt
{node *fg =mknode("",$1,$3,""); $$ = mknode("recive:",fg,$5,"");}
|multidentifier COLON identifiertype{$$ = mknode("recive:",$1,$3,"");}
;
compondStmt: BRACES{$$=$1;}
|SEMICOLON{$$ = mknode("",NULL,NULL,"");}
;
functionCall: iden LEFTPAREN sendArgs RIGHTPAREN{node *Sgl = mknode("(",$3,NULL,")");$$= mknode("",$1,Sgl,"");}
|iden LEFTPAREN RIGHTPAREN {node *Sgg = mknode("(",NULL,NULL,")");$$= mknode("",$1,Sgg,"");}
;
sendArgs: return_val {$$=$1;}
|sendArgs COMMA return_val {node *SA = mknode("",$1,NULL,",");$$= mknode("",SA,$3,"");}
;
BRACES: LEFTBRACE All RIGHTBRACE {$$ = mknode("\n{BRACES\n",$2,NULL,"\n}");}
|LEFTBRACE RIGHTBRACE{$$ = mknode("\n{BRACES\n",NULL,NULL,"\n}");}
|LEFTBRACE BRACES RIGHTBRACE{$$ = mknode("\n{BRACES\n",$2,NULL,"\n}");}
;
All: RETURN return_val SEMICOLON{$$ = mknode("RETURN",$2,NULL,"\n");}
|All RETURN return_val SEMICOLON{node * K = mknode("RETURN",$2,NULL,"");$$ = mknode("",$1,K,"\n");}
|All function{$$ = mknode("",$1,$2,"\n");}
|function {$$=$1;}
|assignment {$$ = mknode("(",$1,NULL,")\n");}
|assignment SEMICOLON {$$ = mknode("(",$1,NULL,")\n");}
|decleration SEMICOLON{$$=$1;}
|decleration{$$=$1;}
|All decleration SEMICOLON {$$ = mknode("",$1,$2,"\n");}
|All assignment SEMICOLON {$$ = mknode("",$1,$2,"\n");}
|condition{$$=$1;}
|All condition{$$ = mknode("",$1,$2,"\n");}
|All BRACES {$$ = mknode("",$1,$2,"\n");}
|BRACES All {$$ = mknode("",$1,$2,"\n");}
;
return_val: int_num{$$=$1;}
|iden {$$=$1;}
|wstring{$$ = $1;}
|exp{$$=$1;}
|char_id{$$ = mknode(yytext,NULL,NULL,"");}
|bool{$$=$1;}
|wordlength{$$=$1;}
|absolute{$$=$1;}
|identifierabs{$$=$1;}
;
decleration: VAR multidentifier COLON identifiertype {$$ = mknode("",$2,$4,"\n");}
;
multidentifier: iden {$$=$1;}
| multidentifier COMMA iden{node *er = mknode("",$1,NULL,",");$$= mknode("",er,$3,"");}
;
bool: BOOLCONSTANT{$$ = mknode(yytext,NULL,NULL,"");}
;
assignment : iden ASSIGN functionCall {node *pop = mknode("=",$1,NULL,"");$$ = mknode("\t(",pop,$3,")");}
| iden ASSIGN exp {node *rop = mknode("=",$1,NULL,"");$$ = mknode("\t(",rop,$3,")");}
| iden ASSIGN bool{node *nop = mknode("=",$1,NULL,"");$$ = mknode("\t(",nop,$3,")");}
| iden ASSIGN pointeroperator iden
{node *gh= mknode("",$3,$4,"");node *e1 = mknode("=",$1,NULL,"");$$ = mknode("\t(",e1,gh,")");}
| iden ASSIGN iden {node *e2 = mknode("=",$1,NULL,"");$$ = mknode("\t(",e2,$3,")");}
| iden ASSIGN wstring {node *e3 = mknode("=",$1,NULL,"");$$ = mknode("\t(",e3,$3,")");}
| iden ASSIGN char_id{node *e4 = mknode("=",$1,NULL,"");$$ = mknode("\t(",e4,$3,")");}
| iden ASSIGN "null"{node *e5 = mknode("=",$1,NULL,"");$$ = mknode("\t(",e5,NULL,"NULL)");}
;
char_id: CHAR_IDENTIFIER {$$ = mknode(yytext,NULL,NULL,"");}
;
exp: int_num {$$=$1;}
|exp methoperator exp {node *y = mknode(getLT($2),$1,NULL,"");$$ = mknode("(",y,$3,")");}
|LEFTPAREN exp methoperator exp RIGHTPAREN {node *y = mknode(getLT($3),$2,NULL,"");$$ = mknode("(",y,$4,")");}/**/
|iden {$$=$1;}
|LEFTPAREN exp RIGHTPAREN {$$ = mknode("(",$2,NULL,")");}/**/
;
condition: whileCond{$$=$1;}
|ifCond{$$=$1;}
;
ifCond: IF LEFTPAREN innercond RIGHTPAREN BRACES{$$ = mknode("(COND \n",$3,$5,"\n)\n");}
|IF LEFTPAREN innercond RIGHTPAREN BRACES ELSE BRACES{node *yk= mknode("ELSE",$7,NULL,"");
node *j= mknode("",$5,yk,"");$$ = mknode("(COND \n",$3,j,"\n)\n");}
;
whileCond: WHILE LEFTPAREN innercond RIGHTPAREN BRACES {$$ = mknode("(LOOP \n",$3,$5,"\n)\n");}
;
wstring: WORDSTRING{$$ = mknode(yytext,NULL,NULL,"");}
;
condexp: exp signoperator exp {$$ = mknode(getLT($2),$1,$3,"");}
|wstring IsEqual wstring {$$ = mknode(getLT($2),$1,$3,"");}
|iden signoperator exp{$$ = mknode(getLT($2),$1,$3,"");}
|bool{$$=$1;}
|iden IsEqual wstring {$$ = mknode(getLT($2),$1,$3,"");}
|wstring IsEqual iden{$$ = mknode(getLT($2),$1,$3,"");}
|char_id IsEqual char_id {$$ = mknode(getLT($2),$1,$3,"");}
|iden IsEqual char_id {$$ = mknode(getLT($2),$1,$3,"");}
|char_id IsEqual iden{$$ = mknode(getLT($2),$1,$3,"");}
|exp signoperator wordlength {$$ = mknode(getLT($2),$1,$3,"");}
|wordlength signoperator exp {$$ = mknode(getLT($2),$1,$3,"");}
|exp signoperator absolute{$$ = mknode(getLT($2),$1,$3,"");}
|absolute signoperator exp{$$ = mknode(getLT($2),$1,$3,"");}
|wordlength signoperator absolute{$$ = mknode(getLT($2),$1,$3,"");}
|absolute signoperator wordlength {$$ = mknode(getLT($2),$1,$3,"");}
|identifierabs signoperator exp {$$ = mknode(getLT($2),$1,$3,"");}
|identifierabs signoperator wordlength{$$ = mknode(getLT($2),$1,$3,"");}
|identifierabs signoperator absolute{$$ = mknode(getLT($2),$1,$3,"");}
|identifierabs signoperator identifierabs{$$ = mknode(getLT($2),$1,$3,"");}
;
wordlength: ABS_LENGTH wstring ABS_LENGTH {$$ = mknode("|",$2,NULL,"|");}
;
absolute : ABS_LENGTH int_num ABS_LENGTH{$$ = mknode("|",$2,NULL,"|");}
;
identifierabs: ABS_LENGTH iden ABS_LENGTH {$$ = mknode("|",$2,NULL,"|");}
;
innercond: condexp {$$=mknode("\t(",$1,NULL,")");}
|LEFTPAREN condexp RIGHTPAREN{$$ = mknode("(",$2,NULL,")");}
|LEFTPAREN condexp RIGHTPAREN condoperator innercond{node *t = mknode("",$4,$5,"");$$ = mknode("(",$2,t,")");}
|condexp condoperator innercond
{node *lolo = mknode("(",$1,NULL,"");node *Sr = mknode(getLT($2),lolo,NULL,")");$$= mknode(" ",Sr,$3,"");}
|LEFTPAREN condexp condoperator innercond RIGHTPAREN
{node *lili = mknode("(",$2,NULL,"");node *Sr = mknode(getLT($3),lili,NULL,",");$$= mknode(" ",Sr,$4,")");}
;
methoperator: PLUS {$$ = mknode(yytext,NULL,NULL,"");}
|MINUS {$$ = mknode(yytext,NULL,NULL,"");}
|MULTIPLICATION {$$ = mknode(yytext,NULL,NULL,"");}
|DIVISION {$$ = mknode(yytext,NULL,NULL,"");}
;
pointeroperator:ADDRESS {$$ = mknode(yytext,NULL,NULL,"");}
|DEREFERENCE {$$ = mknode(yytext,NULL,NULL,"");}
;
identifiertype: STRING_DECLERATION {$$ = mknode(yytext,NULL,NULL,"");}
|BOOLEAN {$$ = mknode(yytext,NULL,NULL,"");}
|INTEGER {$$ = mknode(yytext,NULL,NULL,"");}
|CHAR {$$ = mknode(yytext,NULL,NULL,"");}
|INTPTR {$$ = mknode(yytext,NULL,NULL,"");}
|CHARPTR {$$ = mknode(yytext,NULL,NULL,"");}
|int_num{$$=$1;}
;
iden : IDENTIFIER {$$ = mknode(yytext,NULL,NULL,"");}
;
signoperator: LESS {$$ = mknode(yytext,NULL,NULL,"");}
|LESSEQUAL {$$ = mknode(yytext,NULL,NULL,"");}
|GREATER {$$ = mknode(yytext,NULL,NULL,"");}
|GREATEREQUAL {$$ = mknode(yytext,NULL,NULL,"");}
|IsEqual {$$=$1;}
;
IsEqual: EQUAL {$$ = mknode(yytext,NULL,NULL,"");}
|NOTEQUAL {$$ = mknode(yytext,NULL,NULL,"");}
;
condoperator: AND {$$ = mknode(yytext,NULL,NULL,"");}
|OR {$$ = mknode(yytext,NULL,NULL,"");}
;
int_num: INTEGER_CONST {$$ = mknode(yytext,NULL,NULL,"");}
|BINARY_NUMBER {$$ = mknode(yytext,NULL,NULL,"");}
|OCTAL_NUMBER {$$ = mknode(yytext,NULL,NULL,"");}
|HEX_NUMBER {$$ = mknode(yytext,NULL,NULL,"");}
;
%%
#include "lex.yy.c"
int main()
{
return yyparse();
}
node* mknode(char * ltoken, node * left, node * right,char * rtoken)
{
node * newnode = (node*)malloc(sizeof(node));
char * newstr = (char*)malloc(sizeof(ltoken)+1);
strcpy(newstr, ltoken);
char * newstrr = (char*)malloc(sizeof(rtoken)+1);
strcpy(newstrr, rtoken);
newnode->left = left;
newnode->right = right;
newnode->ltoken = newstr;
newnode->rtoken = newstrr;
return newnode;
}
void printtree(node * tree)
{
printf("%s ", tree->ltoken);
if (tree->left)
printtree(tree->left);
if (tree->right)
printtree(tree->right);
printf("%s ", tree->rtoken);
}
int yyerror(char* s)
{
extern int yylineno;
printf("yacc error: %s at line %d\n",s,yylineno); return 0;
}
char * getLT(node * s)
{
return s->ltoken;
}
我运行调试,我理解为什么所有这些冲突,但我真的不明白这意味着什么。
这是我的调试输出(我添加链接,因为它是长文档)
答案 0 :(得分:0)
冲突不是错误,它们基本上意味着解析器生成器无法决定在某些阶段应用哪个规则。转换/减少冲突是指您可以完成规则(减少)或使用下一个令牌(转移)并从该状态继续。典型的shift / reduce问题是if-else语句:
if condition
if another condition
# Do something...
else
# Do something else
if分支属于哪个if语句?看看这个:
IF <condition> <statement> IF <condition> <statement> ELSE <statement>
The parser is here ^
如果解析器决定移位,那么else分支将成为内部语句的一部分,但如果它减少,则外部语句将拥有它。通常,通过转移而不是减少来处理转移 - 减少冲突。
现在,当您的语法中出现致命错误时会发生减少 - 减少冲突,因为2条规则适用于同一输入。例如:
sequence:
%empty { printf ("empty sequence\n"); }
| maybeword
| sequence word { printf ("added word %s\n", $2); }
;
maybeword:
%empty { printf ("empty maybeword\n"); }
| word { printf ("single word %s\n", $1); }
;
所以看看你的语法,找到那些减少 - 减少的冲突!
如果你只是学习解析,你应该考虑的事情,尝试首先推出自己的解析器(如自上而下的递归下降解析器)!它并不是那么糟糕,你将使用的最复杂的算法可能是数学表达式的分流码算法。此外,您将受益于更好的错误处理和自定义语法,无法使用解析器生成器解析(无需黑客攻击)。