Parsing 如何为给定语言实现语义检查器
假设我们有一个语义规则,当调用函数时,函数应该在当前范围或父范围中声明 所以既然foo();没有在上面的程序中声明(第3行),我们需要打印一条错误消息 对于第13行,hello()未声明,因此我们需要打印一条错误消息 我们有bison/flex实现,但是缺少属性语法实现 解析器:Parsing 如何为给定语言实现语义检查器,parsing,compiler-construction,bison,semantics,lex,Parsing,Compiler Construction,Bison,Semantics,Lex,假设我们有一个语义规则,当调用函数时,函数应该在当前范围或父范围中声明 所以既然foo();没有在上面的程序中声明(第3行),我们需要打印一条错误消息 对于第13行,hello()未声明,因此我们需要打印一条错误消息 我们有bison/flex实现,但是缺少属性语法实现 解析器: for(var x in z) { a = x + 1 + 2; foo(); } function bar() {} for(t in []){ function hello(a) { a = t +
for(var x in z) {
a = x + 1 + 2;
foo();
}
function bar() {}
for(t in []){
function hello(a) {
a = t + 'hello' + 'world';
}
bar();
hello();
}
hello();
function hello() {}
15 * 30;
1 + 2 + 3;
a = 3 - 2 - 1;
a + 10;
%{
#包括
无效错误(常量字符*消息){
printf(“%s\n”,msg);
}
%}
%在tVAR tCOMMA tRPAR tRBRKT TRBRATE tGT tEQ tMINUS TNO tIF tIF tCOLON TLBRATE tEQCHECK T功能运行期间,为锡tSEMICOLON tLPAR tLBRKT tLT tLT tLT tSTAR tPLUS tPLUS T百分之三的色流管柱标记
%左tMINUS tPLUS
%左塔
%左t%
%左tLT tGT tEQCHECK
%左tNOT
%%
程序:语句列表
;
语句列表:语句列表语句
|语句列表tSEMICOLON
|
;
声明:分配
|如果
|expr
|当
|为了
|函数调用
|功能声明
;
分配:tIDENT tEQ expr
|tVAR tIDENT tEQ expr
;
if:ifPart elsePart
;
ifPart:tIF tLPAR expr tRPAR语句块
;
elsePart:tELSE语句块
|
;
while:twile tLPAR expr tRPAR语句块
;
for:t对于tLPAR tIDENT TIND tIN expr tRPAR语句块
|t对于tLPAR tVAR tIDENT TIND TIND expr tRPAR语句块
;
functionDeclaration:tFUNCTION tIDENT tLPAR exprList tRPAR语句块
|t功能提示tLPAR tRPAR语句块
;
语句块:tLBRACE语句列表tRBRACE
;
函数调用:tIDENT tLPAR exprList tRPAR
|tIDENT tLPAR tRPAR
;
实验:潮水
|特雷尔
|色调
|tSTRING
|tLBRKT tRBRKT
|tLBRKT exprList tRBRKT
|TLBREACE TRBREACE
|tLBRACE属性列表tRBRACE
|tNOT expr
|expr tPLUS expr
|expr tMINUS expr
|expr tSTAR expr
|expr TECQCHECK expr
|expr tLT expr
|expr tGT expr
;
exprList:expr
|exprList tCOMMA expr
;
propertyList:tIDENT Tclon expr
|属性列表tCOMMA tIDENT tCOLON expr
;
%%
int main(){
返回yyparse();
}
扫描仪:
%{
#include <stdio.h>
void yyerror(const char * msg){
printf("%s\n",msg);
}
%}
%token tFOR tIN tSEMICOLON tLPAR tLBRKT tLT tSTAR tPLUS tPERCENT tINT tREAL tSTRING tWHILE tVAR tCOMMA tRPAR tRBRKT tRBRACE tGT tEQ tMINUS tNOT tIDENT tIF tCOLON tLBRACE tELSE tEQCHECK tFUNCTION
%left tMINUS tPLUS
%left tSTAR
%left tPERCENT
%left tLT tGT tEQCHECK
%left tNOT
%%
prog: statementList
;
statementList: statementList statement
| statementList tSEMICOLON
|
;
statement: assign
| if
| expr
| while
| for
| functionCall
| functionDeclaration
;
assign: tIDENT tEQ expr
| tVAR tIDENT tEQ expr
;
if: ifPart elsePart
;
ifPart: tIF tLPAR expr tRPAR statementBlock
;
elsePart: tELSE statementBlock
|
;
while: tWHILE tLPAR expr tRPAR statementBlock
;
for: tFOR tLPAR tIDENT tIN expr tRPAR statementBlock
| tFOR tLPAR tVAR tIDENT tIN expr tRPAR statementBlock
;
functionDeclaration: tFUNCTION tIDENT tLPAR exprList tRPAR statementBlock
| tFUNCTION tIDENT tLPAR tRPAR statementBlock
;
statementBlock: tLBRACE statementList tRBRACE
;
functionCall: tIDENT tLPAR exprList tRPAR
| tIDENT tLPAR tRPAR
;
expr: tIDENT
| tREAL
| tINT
| tSTRING
| tLBRKT tRBRKT
| tLBRKT exprList tRBRKT
| tLBRACE tRBRACE
| tLBRACE propertyList tRBRACE
| tNOT expr
| expr tPLUS expr
| expr tMINUS expr
| expr tSTAR expr
| expr tEQCHECK expr
| expr tLT expr
| expr tGT expr
;
exprList: expr
| exprList tCOMMA expr
;
propertyList: tIDENT tCOLON expr
| propertyList tCOMMA tIDENT tCOLON expr
;
%%
int main() {
return yyparse();
}
%{
#包括“parser.tab.h”
%}
%%
作为回报;
函数返回t函数;
用于返回tFOR;
一会儿回来;
var-return-tVAR;
","返回采美克隆,;
“(“返回tLPAR;
“)返回tRPAR;
“[”返回tLBRKT;
“]”返回tRBRKT;
“返回tGT;
“*”返回tSTAR;
“+”返回tplu;
“%”返回t百分比;
“,”返回tCOMMA;
“{”返回括号;
“}”返回括号;
“==”返回TechCheck;
“=”返回tEQ;
“-”返回tMINUS;
“!”返回tNOT;
“-”?[0-9]+返回色调;
(“-”[0-9]+”[0-9]+)|([0-9]*”[0-9]+)返回tREAL;
('[^']*')|([“][^”]*[“])返回tSTRING;
[a-zA-Z_][a-zA-Z_0-9]*回潮;
[\t\n]
.返回文本[0];
%%
在下面的语法中tIDENT
和t函数
是标记。Foo()
是标记。
你必须保持冷静
符号表
为了存储tIDENT
或t函数
令牌。要检查foo
是否已声明,必须遍历符号表并查看它是否已在其中。还必须使用变量执行此操作
例如:
%{
#include "parser.tab.h"
%}
%%
in return tIN;
function return tFUNCTION;
for return tFOR;
while return tWHILE;
var return tVAR;
";" return tSEMICOLON;
"(" return tLPAR;
")" return tRPAR;
"[" return tLBRKT;
"]" return tRBRKT;
"<" return tLT;
">" return tGT;
"*" return tSTAR;
"+" return tPLUS;
"%" return tPERCENT;
"," return tCOMMA;
"{" return tRBRACE;
"}" return tLBRACE;
"==" return tEQCHECK;
"=" return tEQ;
"-" return tMINUS;
"!" return tNOT;
"-"?[0-9]+ return tINT;
("-"[0-9]+"."[0-9]+)|([0-9]*"."[0-9]+) return tREAL;
('[^']*')|(["][^"]*["]) return tSTRING;
[a-zA-Z_][a-zA-Z_0-9]* return tIDENT;
[ \t\n]
. return yytext[0];
%%
您必须实现自己的符号表及其功能,例如用C语言在符号表中添加和搜索。此处symlook
在符号表中搜索,如果未找到标记t功能($1)
inside将生成错误消息。您还必须在其中包含不同的语法。一个是函数或可验证项第一次声明时的语法,另一个是在表达式中找到它时的语法。
检查此C Yacc语法。这些是C语言的产品:
见此:
assign: tFUNCTION {
SYMBOL *s= NULL
if((s=symlook_function($1,depth,yylineno,param_count,symbol_list)) == NULL ){
strcat(errstr, "Found a function which is not decalared");
yyerror(errstr);
}
}
当产品为function\u definition
时,令牌foo
第一次进入符号表。但是,如果您在不同的产品中再次找到foo
,则必须搜索符号表,如果缺少,则返回error
。不清楚这是一般问题还是错误特定于bison/flex的使用?如果是前者,这是一个非常广泛的问题。也许缩小到特定范围会有所帮助。>>“我们有bison/flex实现,但缺少属性语法实现。”是的。实现其中一个来进行语义检查。
external_declaration
: function_definition
| declaration