我正在尝试为c编写解析器。我得到的错误是:“减少/减少冲突”
1)规则 exp 需要转到 IDENTIFIER 例如: a-b (标识符 - 标识符) - >的 EXP-EXP - >的 EXP
2)规则 ident_list 也需要转到 IDENTIFIER 。此规则用于变量声明。 例如: a,b,c (标识符,标识符,标识符) - > ident_list 。
因此我需要两个规则, ident_list 和 exp 转到 - > IDENTIFIER 。这导致“减少/减少”冲突”。知道如何解决这个问题吗?
-------------*yac code*:---------------
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
char* token;
struct node* left;
struct node* right;
char* type;
}node;
typedef struct obj
{
char* type;
char* name;
struct obj* next;
}obj;
typedef struct symTbl
{
struct obj* first;
struct obj* last;
int size;
}symTbl;
node* mknode (char* token,node* left, node* right,char* Type);
void put(symTbl* tbl, char* type,char* name);
void printtree(node* tree);
#define YYSTYPE struct node*
%}
%start s
%token WHILELOOP
%token STATIF
%token ELSE
%token MAIN
%token POINTERERR
%token COMMENT
%token POINTER
%token GREATEREQUAL
%token LESSEREQUAL
%token DBLAND
%token GREATER
%token LESSER
%token POWER
%token MULTIPLY
%token MINUS
%token PLUS
%token AND
%token OR
%token NOT
%token NOTEQUAL
%token CHARERROR
%token STRINGERROR
%token POINTER
%token INTEGER
%token BOOLEAN
%token DEVIDE
%token ASSIGN
%token EQUAL
%token TYPE
%token IDENTIFIER
%token HEX IF
%token LITERCHAR
%token OCTAL
%token BINARYINT
%token LTRLSTRING
%token COMMA COLON SEMICOLON VAR RETURN RPARENC LPARENC
%left COMMA LPAREN RPAREN ELSE
%left PLUS IF WHILELOOP TYPE
%left MINUS DEVIDE RPARENC LPARENC
%left MULTIPLY EQUAL NOTEQUAL OR AND LESSEREQUAL GREATEREQUAL GREATER LESSER
%%
s:progrem{printtree($1);}
progrem:exp|var_dec|if_stnt|ident_list|bool_exp| mul_ident;
exp: exp PLUS exp{$$=mknode("+",$1,$3,"arit");}
|exp MINUS exp {$$=mknode("-",$1,$3,"arit");}
|exp DEVIDE exp {$$=mknode("/",$1,$3,"arit");}
|exp MULTIPLY exp {$$=mknode("*",$1,$3,"arit");}
|MINUS exp {$$=mknode("-",$2,NULL,"arit");}
|IDENTIFIER {$$=mknode(yytext,NULL,NULL,"id");}
|LPAREN exp RPAREN {$$= $2;};
bool_exp : exp EQUAL exp {$$=mknode("=",$1,$3,"bool");}
|exp NOTEQUAL exp {$$=mknode("!=",$1,$3,"bool");}
|exp OR exp {$$=mknode("||",$1,$3,"bool");}
|exp AND exp {$$=mknode("&&",$1,$3,"bool");}
|exp GREATEREQUAL exp {$$=mknode(">=",$1,$3,"bool");}
|exp LESSER exp {$$=mknode("<",$1,$3,"bool");}
|exp LESSEREQUAL exp {$$=mknode("<=",$1,$3,"bool");}
|exp GREATER exp {$$=mknode(">",$1,$3,"bool");}
|LPAREN bool_exp RPAREN {$$= $2;};
var_dec:ident_list COLON ident_list {$$=mknode(":",$1,$3,"dec");};
ident_list: ident_list COMMA ident_list {$$=mknode(",", $1, $3,"id_list");}
|ident_list TYPE ident_list{$$=mknode(yytext,$1,NULL,"id");}
|VAR {$$= mknode("var",NULL,NULL,"id");}
|SEMICOLON {$$= mknode(";",NULL,NULL,"id");};
|IDENTIFIER {$$=$1;}
if_stnt:IF LPAREN bool_exp RPAREN {$$=mknode("if",$3,NULL,"if_state");};
%%
#include "lex.yy.c"
main()
{
yyin=fopen("text.txt","r");
return yyparse();
}
node* mknode( char* token,node*left,node* right,char* Type)
{
node* newnode=(node*)malloc(sizeof(node));
char* newstr=(char*)malloc(sizeof(token)+1);
char* type = (char*)malloc (sizeof(Type)+1);
type[sizeof(token)]='\0';
newstr[sizeof(token)]='\0';
strcpy(newstr,token);
strcpy(type,Type);
newnode->left=left;
newnode->type=type;
newnode->right=right;
newnode->token=newstr;
return newnode;
}
void put(symTbl* tbl, char* type,char* name)
{
symTbl* tbl1=(symTbl*)malloc(sizeof(symTbl));
int size = tbl->size;
obj* newobj=(obj*)malloc(sizeof(obj));
newobj= tbl->first;
int i;
for( i =0; i<size; i++){
if(newobj->name == name){
yyerror();
newobj=newobj->next;
}
}
tbl->last->next=newobj;
tbl->last=tbl->last->next;
}
void printtree(node* tree)
{
printf("%s",tree->token);
if(tree->left)printtree(tree->left);
if(tree->right)printtree(tree->right);
}
int yyerror()
{
printf("bla bla\n");
return 0;
}
-------- lex code :------------
minus "-"
colon ":"
semicolon ";"
space " "
parcent "%"
backslash "/"
charptr charptr
plus "+"
not "!"
notequal "!="
or "||"
and "&&"
multiply "*"
power "^"
dbland "&"
greater ">"
lesser "<"
type boolean|string|char|integer|intptr|charptr
return "return"
greaterequal {greater}{assign}
lesserequal {lesser}{assign}
singleQuotes \'
charERR {singleQuotes}+(({digit})+)*(({letter})+)*{singleQuotes}+
stringERR {doubleQuotes}{doubleQuotes}+|{doubleQuotes}
doubleQuotes \"
var "var"{space}*
octalDigit [1-7]
decimal {digit}|{digitNoZero}{digit}+
digitNoZero[1-9]
octal "0"{octalDigit}("0")*{octalDigit}*
integer {binaryInt}|{hex}|{octal}|{decimal}
binaryInt ("0"|"1")+"b"
hexLetter A|B|C|D|E|F
hex 0(x|X){digit}+{hexLetter}*|0(x|X){digit}*{hexLetter}+
literBool true|false
letter [a-zA-Z]
letters {letter}+
digit [0-9]
low "_"
equal "=="
assign "="
devide "/"
lparen "("
rparen ")"
lparenc "{"
rparenc "}"
identifier {letter}+{digit}*{letter}+{space}*|{space}*{letter}{space}*
literChar {singleQuotes}{letter}{singleQuotes}
ltrlString {doubleQuotes}{letters}*{decimal}*{hex}*{octal}*{binaryInt}*{dbland}*{devide}*{assign}*{equal}*{greater}*{lesser}*{greaterequal}*{lesserequal}*{mi$
pointer {colon}{space}{charptr}|"="{space}"&"{identifier}
comment {backslash}{parcent}{space}*({letters}*{space}*{identifier}*{space}*{decimal}*{space}*{hex}*{space}*{octal}*{space}*{binaryInt}*{space}*{dbland}*{dev$
pointerErr "&"{identifier}|{charptr}
statif "if"{space}*
ELSE "else"{space}*
comma ","
whileLoop "while"{space}*
main "main"
%%
{lparen} return LPAREN;
{rparen} return RPAREN;
{colon} return COLON;
{type} return TYPE;
{semicolon} return SEMICOLON;
{var} return VAR;
{whileLoop} return WHILELOOP;
{ELSE} return ELSE;
{statif} return IF;
{pointerErr} return POINTERERR;
{comment} return COMMENT;
{pointer} return POINTER;
{literChar} return LITERCHAR;
{charERR} return CHARERROR;
{stringERR} return STRINGERROR;
{ltrlString} return LTRLSTRING;
{binaryInt} return BINARYINT;
{octal} return OCTAL;
{hex} return HEX;
{return} return RETURN;
{greaterequal} return GREATEREQUAL;
{lesserequal} return LESSEREQUAL;
{dbland} return DBLAND;
{greater} return GREATER;
{lesser} return LESSER;
{lparenc} return LPARENC;
{rparenc} return RPARENC;
{power} return POWER;
{multiply} return MULTIPLY;
{plus} return PLUS;
{or} return OR;
{and} return AND;
{comma} return COMMA;
{not} return NOT;
{main} return MAIN;
{notequal} return NOTEQUAL;
{minus} return MINUS;
{integer} return INTEGER;
{literBool} return BOOLEAN;
{identifier} return IDENTIFIER;
{equal} return EQUAL;
{assign} return ASSIGN;
{devide} return DEVIDE;
. return yytext[0];
答案 0 :(得分:1)
您说program
可以是exp
或ident_list
等等。这开始并不是特别明智,我想你的意图是进行某种调试。但它不会起作用,因为单个标识符可能是一个表达式或只包含一个标识符的列表,并且解析器没有明显的方法来猜测你的意思。这使你的语法模棱两可。
在这种情况下,yacc / bison的作用是选择语法文件中较早出现的生产。这不是定义偏好的非常精确的方式,因此它会警告您冲突。但它可以让你表达自己的偏好。
否则,您必须消除歧义。例如,如果您确定单个标识符应为exp
,则可以坚持顶级标识符列表至少包含两个标识符。