Parsing 如何为给定语言实现语义检查器

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 +

假设我们有一个语义规则,当调用函数时,函数应该在当前范围或父范围中声明

所以既然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 + '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