Compiler Construction using Flex and Bison(译4--上下文)

本文介绍如何使用Lex和Bison处理上下文敏感信息,通过构建符号表来确保变量在引用前已声明。文章详细说明了符号表的设计与实现,并展示了如何修改语法分析器以进行上下文检测。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lex和Bison文件可以扩展以处理上下文敏感信息.例如,为简单起见,假设我们想要求这样,我们要求变量在引用前必须先声明.因此,语法分析器应该可以把变量引用与变量声明对比.(看是否一致)
为了完成这些,一种方法是当语法分析到一个变量构造一个变量列表,而当分析到变量引用时从变量列表中检测变量引用.这样的列表称为符号表.符号表可以用链表,树和哈希表实现.
我们修改Lex文件,把标识符的字符串信息赋给全局变量yylval,因为这些信息将在属性文法用到.

符号表模块
为了保存属性文法所需要的信息,我们构造一个符号表.一个符号表包含关于各种程序设计语言结构的属性的环境信息.特别地,应包含类型和作用域信息.

符号表将被作为一个模块包含在yacc/bison的文件中.

Simple的符号表包含一条标识符的链表,初始为空.这里是一个链表结点的声明,初始链表为空,和两个操作:putsym把一个标识符放入表中,而getsym返回一个与标识符一致的符号表项的指针.
struct symrec
{
char * name; /*name of symbol*/
struct symrec *next; /*link field*/
};
typedef struct symrec symrec;
symrec *sym_table = (symrec *)0;
symrec *putsym();
symrec *getsym();

symrec*
putsym ( char *sym_name) /*头插入*/
{
symrec *ptr;
ptr = (symrec *)malloc(sizeof(symrec));
ptr -> name =(char *)malloc(strlen(stm_name)+1);
strcpy(ptr->name,sym_name);
ptr->next = (struct symrec *)sym_table;
sym_table = ptr;
return ptr;
}

symrec *
getsym ( char *sym_name)
{
symrec *ptr;
for (ptr=sym_table;ptr!=(symrec *)0;
ptr = (symrec *)ptr->next)
if(strcmp(ptr->name,sym_name)==0)
return ptr;
return 0;
}

语法分析器修改

Yacc/Bison文件被修改成包含符号表和其相应的操作函数,以执行把标识符装入到符号表中和上下文检测.

%{
#include <stdlib.h> /*For malloc in symbol table*/
#include <string.h> /*For strcmp in symbol table*/
#include <stdio.h> /*For error message */
#include "ST.h"  /* The Symbol Table Module */
#define YYDEBUG 1 /*For debugging */
install ( char *sym_name)
{
symrec *s;
s = getsym (sym_name);
if (s==0)
s = putsym (sym_name);
else{errors++;
printf ( "%s is already defined/n",sym_name);
}
}
context_check( char *sym_name)
{if ( getsym( sym_name ) = =0)
printf( "%s is an undeclared identifier/n",sym_name);
}
%}
Parser declarations
%%
Grammar rules and actions
%%
C subroutines

因为扫瞄器(Lex文件)将返回标识符,所以要求用静态语义记录保存其值,而IDENT与这静态语义记录关联.

C declarations
%union{ /*SEMANTIC RECORD*/
char *id; /*For returning identifier */
}
%token INT SKIP IF THEN ELSE FI WHILE DO END
%token <id> IDENT /* Simple identifier */
%left '-' '+'
%left '*' '/'
%right '^'
%%
Grammar rules and actions
%%
C subroutines

非终结符...

 上下文无关文法修改包含intall和上下文检测函数调用.$n是Yacc的内部变量,它指引用与产生式右部第n个符号一致的语义记录.$$指与产生式左部非终结符一致的语义录.

C and parser declarations
%%
...
declarations : /* empty */
| INTEGER id_seq IDENTIFIER '.' { install( $3); }
;
id_seq : /* empty */
| id_seq IDENTIFIER ',' {install($2);}
;
command : SKIP
| READ IDENTIFIER {context_check( $2 );}
| IDENT ASSGNOP exp {context_check( $2 );}
...
exp : INT
| IDENT { context_check( $2 ); }
...
%%
C subroutines

语法分析树的实现隐式包含关于一个变量在表达式引用之前是否已被赋值的注释信息.语法树的注释信息被收集到符号表中.

扫瞄器修改

扫瞄器必须修改成返回与标识符相关联的字符常量.(记号的语义值).语义值通过yylval返回.yylval的类型是一个在语法分析文件中用%union定义的联合体.语义值必须存放在合适的联合体成员中.因为联合体声明如下:
%union{ char *id;
}
所以语义值是由全局变量yytext(包含输入文本)复制到yylval.id中.因为函数strdup被用到(string.h中定义),所以这个头文件必须包含.扫瞄器文件最终改为:

%{
#include <string.h>  /*for strdup */
#include "Simple.tab.h" /* for token definitions and yylval */
%}
DIGIT   [0-9]
ID    [a-z][a-z0-9]
%%
":="    {return (ASSGNOP); }
{DIGIT}+  {return (NUMBER); }
do    {return (DO )  ; }
else    {return (ELSE)   ; }
end    { return (END) ;}
fi    { return (FI)  ; }
if    { return (IF)  ; }
in    { return (IN)  ; }
integer   { return (INGETER);}let    { return (LET)  ; }
read    { return (READ)  ; }
skip    { return (SKIP)  ; }
then    { return (THEN) ; }
while   { return (WHILE) ; }
write   { return (WRITE) ; }
{ID}   { yylval.id = (char *) strdup(yytext);
return (IDENTIFIER) ;}
[ /t/n]+   /* eat up whiteespace */
.    { return (yytext[0] ) ; }
%%

中间表示

许多编译器在语法分析阶段把源代码转为中间表示.在我们的例子中,语法表示是一个语法树.语法树保留在栈中但它可以显示构造.另一些中间表示通用的选择包括抽象语法树,三元地址,当然也有四元地址,和后缀码.在我们的例子中,我们选择跳过中间表示而直接生成代码.这节说到有关代码生成的原则也适用于中间代码生成.

内容概要:本文详细介绍了900W或1Kw,20V-90V 10A双管正激可调电源充电机的研发过程和技术细节。首先阐述了项目背景,强调了充电机在电动汽车和可再生能源领域的重要地位。接着深入探讨了硬件设计方面,包括PCB设计、磁性器件的选择及其对高功率因数的影响。随后介绍了软件实现,特别是程序代码中关键的保护功能如过流保护的具体实现方法。此外,文中还提到了充电机所具备的各种保护机制,如短路保护、欠压保护、电池反接保护、过流保护和过温度保护,确保设备的安全性和可靠性。通讯功能方面,支持RS232隔离通讯,采用自定义协议实现远程监控和控制。最后讨论了散热设计的重要性,以及为满足量产需求所做的准备工作,包括提供详细的PCB图、程序代码、BOM清单、磁性器件和散热片规格书等源文件。 适合人群:从事电力电子产品研发的技术人员,尤其是关注电动汽车充电解决方案的专业人士。 使用场景及目标:适用于需要高效、可靠充电解决方案的企业和个人开发者,旨在帮助他们快速理解和应用双管正激充电机的设计理念和技术要点,从而加速产品开发进程。 其他说明:本文不仅涵盖了理论知识,还包括具体的工程实践案例,对于想要深入了解充电机内部构造和工作原理的人来说是非常有价值的参考资料。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值