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;
假设我们有一个语义规则,即在调用函数时,该函数应在当前作用域或父作用域之前声明。
所以自从foo();在上面的程序(第3行)中没有声明我们需要打印错误信息。
对于第13行,未声明hello(),因此我们需要打印错误消息。
我们有bison / flex实现,但缺少属性语法实现。
分析器:
%{
#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();
}
扫描仪:
%{
#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];
%%
答案 0 :(得分:0)
以下语法tIDENT
和tFUNCTION
是令牌。Foo()
是令牌。
你必须保持
符号表
为了存储tIDENT
或tFUNCTION
令牌。要检查之前是否已声明foo
,您必须遍历符号表并查看它是否已经在里面。您必须这样做这也有变量。
例如:
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);
}
}
您必须实现自己的符号表及其功能,例如在C语言中添加和搜索。在symlook
内搜索符号表,如果它没有找到令牌{{1 }} tFUNCTION
inside会产生一条错误信息。你还必须在里面包含不同的语法。当一个函数或者veriable第一次($1)
时,你可以在declaring
找到它
检查这个C Yacc语法。这些是C语言的产生:
https://www.lysator.liu.se/c/ANSI-C-grammar-y.html
看到这个:
an expression.
当制作为external_declaration
: function_definition
| declaration
时,令牌function_definition
首次进入符号表内。如果您再次在另一个制作中找到foo
,则必须搜索符号表,如果缺少则返回foo
。