Lex和Yacc符号表的生成和操作

Lex和Yacc符号表的生成和操作,c,compiler-errors,C,Compiler Errors,我正在尝试构建一个简单的C编译器,在词法分析阶段使用lex,在语法分析阶段使用yacc。我正在用lex构建符号表,并用我在词法分析中遇到的所有标识符(现在只是标识符的名称、行号和范围)填充它。符号表本身是链表的形式,指针指向链表的头部。现在,我希望能够访问yacc中的这个符号表来更新每个标识符的值和数据类型。如何访问yacc中的符号表 我已经在lex中将头指针定义为extern,但它没有帮助。这是完整的代码供参考- 法(ngrammar.l)— %{ #包括 #包括 #包括 #定义最大1000

我正在尝试构建一个简单的C编译器,在词法分析阶段使用lex,在语法分析阶段使用yacc。我正在用lex构建符号表,并用我在词法分析中遇到的所有标识符(现在只是标识符的名称、行号和范围)填充它。符号表本身是链表的形式,指针指向链表的头部。现在,我希望能够访问yacc中的这个符号表来更新每个标识符的值和数据类型。如何访问yacc中的符号表

我已经在lex中将头指针定义为extern,但它没有帮助。这是完整的代码供参考-

法(ngrammar.l)—

%{
#包括
#包括
#包括
#定义最大1000
外部国际组织;
int scope=0;
int lineno=1;
int-paran=0;
类型定义结构节点{
整数指数;
int范围;
字符符号[MAX];
字符行号[MAX];
字符类型[MAX];
字符值[MAX];
结构节点*下一步;
}节点;
外节点*头部;
head=NULL;
节点*插入符号(节点*,int,字符*,int,int);
无效显示(节点*头部);
节点*插入符号(节点*头、int范围、char*符号、int行号、int paran){
如果(paran>0){
范围++;
}
否则{;
}
if(head==NULL){
node*temp=(node*)malloc(sizeof(node));
温度->指数=1;
温度->范围=范围;
strcpy(临时->符号,符号);
char-str[4];
sprintf(str,“%d”,行号);
strcpy(临时->线路号,str);
temp->next=NULL;
压头=温度;
}
否则{
节点*cur=头部;
node*prev=NULL;
int present=0;
while(cur!=NULL){
if((cur->scope==scope)&&(strcmp(cur->symbol,symbol)==0)){
char-str[4];
sprintf(str,,%d),行号;
strcat(当前->线路号,str);
当前=1;
}
prev=cur;
cur=cur->next;
}
如果(当前==0){
node*temp=(node*)malloc(sizeof(node));
临时->索引=(上一个->索引)+1;
温度->范围=范围;
strcpy(临时->符号,符号);
char-str[4];
sprintf(str,“%d”,行号);
strcpy(临时->线路号,str);
temp->next=NULL;
上一个->下一个=温度;
}
}
回流头;
}
无效显示(节点*头部){
节点*p=头部;
printf(“\t\t\t符号表\t\t\n\n”);
printf(“\t Index\t\t Symbol\t Scope\t\t行号\n”);
if(p==NULL){
printf(“无”);
返回;
}
否则{
while(p!=NULL){
//printf(“输入”);
printf(“\t%d\t\t%s\t\t%d\t\t%s\n”,p->index,p->symbol,p->scope,p->lineno);
p=p->next;
}
}
}
%}
α[A-Za-z]
数字[0-9]
和
空格[]
选项卡[]
行[\n]
acc[^“*/”]
str[^\“]
%%
\/\/(.*)[\n]*{;}
\/\*({acc}*\n)*{acc}*\*\/[\n]*{;}
for{return for;}
if{返回if;}
char{return char;}
浮点{返回浮点;}
int{return int;}
continue{return continue;}
return{return;}
bool{return bool;}
main{返回main;}
else{return else;}
printf{返回打印;}
中断{返回中断;}
真{return BOOLTRUE;}
FALSE{return BOOLFALSE;}
\|\|{返回或;}
\%d |\%c |\%f{return FORMATSPEC;}
\({返回OPENBRACES;paran++;}
\){return CLOSEBRACES;paran--;}
\{{return OPENCURLYBRACES;scope++;}
\}{return CLOSECURLYBRACES;作用域--;}
[.]{返回点;}
={return ASSIGNOP;}
\+\+|\-\-{return UNARYOP;}
\+|\-|\*|\/{返回ARITHOP;}

>|=|C程序的顶层只能包含声明和定义。它不能包含语句。因此以下内容在C程序的顶层是不合法的:

extern node* head;
head = NULL;
第二行被转换为声明,因为GCC仍然允许使用隐式类型(类型默认为
int
)的前标准C声明。它确实警告了您这一点,但警告没有多大帮助

结果是,上述内容被解释为

extern node* head;
int head = NULL;
这显然是非法的,因为您不能给两个全局定义赋予相同的名称。然后GCC继续使用第二个定义,其余的错误层叠


这与flex或bison无关,与yoir符号表实现也没有什么关系,我没有看过。但这很好地说明了为什么在编写解析器时,您应该考虑生成好的错误消息。

请不要使用屏幕截图。它们在移动设备上很难阅读,这是不可能的le需要从中复制以在答案中进行说明。只需将错误作为(文本)代码块粘贴到问题中即可。谢谢。还有一些其他问题。您需要为token for、yyerror()等声明转发声明。相反,请使用Flex和Bison,并为每个错误生成头文件,然后在序言中包含头文件(在.l和.y文件的第一个%%之前的“{”%}”之间的代码。为yyerror()添加前向decl这里也是。不要将lex.yy.c包含在.y文件中。分别编译每个.c文件。此外,您还有shift/shift和shift/reduce错误。@kaby76:该代码确实存在许多问题。不过,本网站的组织理念是:一个问题及其答案解决一个特定的问题,从而使它们对具有相同问题的其他程序员有用。这个问题当然是特定的,这很好,我试图用这些术语来回答它,我相信OP会在必要时提出另一个问题,以解决他们自己无法解决的其他问题。
extern node* head;
head = NULL;
extern node* head;
int head = NULL;