注意:
1.本程序用的是LL1预测分析表法。
2.可根据输入的文法文件自动生成first集、follow集、select集以及预测分析表。
3.文法的符号之间要有空格。
4.最后的输出文件有set.txt,parseResult.txt,tree.xml。
5.编程环境是:
操作系统:Deepin
IDE: CLion
一、
CMM语言在实验所要求的基础上增加了for循环结构、自增运算、自减运算、复合运算符如+=、方法调用等。具体文法如下:
<程序> -> <函数定义或声明> <程序>
<程序> -> $
<函数定义或声明> -> <类型> <变量> ( <参数声明> ) <函数定义或声明闭包>
<函数定义或声明闭包> -> <复合函数块>
<函数定义或声明闭包> -> ;
<类型> -> int
<类型> -> real
<变量> -> <标识符> <数组下标>
<标识符> -> ID
<数组下标> -> [ <因式> ]
<数组下标> -> $
<因式> -> ( <表达式> )
<因式> -> <变量>
<因式> -> <数字>
<因式> -> $
<数字> -> INT_VALUE
<数字> -> FLOAT_VALUE
<表达式> -> <一元表达式>
<表达式> -> <因子> <项>
<一元表达式> -> <前缀表达式>
<一元表达式> -> <后缀表达式>
<前缀表达式> -> <自增减运算符> <变量>
<后缀表达式> -> <变量> <自增减运算符>
<自增减运算符> -> ++
<自增减运算符> -> --
<因子> -> <因式> <因式递归>
<因式递归> -> * <因式> <因式递归>
<因式递归> -> / <因式> <因式递归>
<因式递归> -> % <因式> <因式递归>
<因式递归> -> $
<项> -> + <因子> <项>
<项> -> - <因子> <项>
<项> -> $
<参数声明> -> <声明> <声明闭包>
<参数声明> -> $
<声明> -> <类型> <变量> <赋初值>
<赋初值> -> = <右值>
<赋初值> -> $
<右值> -> <表达式>
<右值> -> { <多个数据> }
<多个数据> -> <数字> <数字闭包>
<数字闭包> -> , <数字> <数字闭包>
<数字闭包> -> $
<声明闭包> -> , <声明> <声明闭包>
<声明闭包> -> $
<复合函数块> -> { <函数块> }
<函数块> -> <声明语句闭包> <函数块闭包>
<声明语句闭包> -> <声明语句> <声明语句闭包>
<声明语句闭包> -> $
<声明语句> -> <声明> ;
<函数块闭包> -> <赋值函数> <函数块>
<函数块闭包> -> <for循环> <函数块>
<函数块闭包> -> <while循环> <函数块>
<函数块闭包> -> <条件语句> <函数块>
<函数块闭包> -> <函数返回> <函数块>
<函数块闭包> -> $
<赋值函数> -> <自增减运算符> <变量> ;
<赋值函数> -> <类型> <变量> <赋值或函数调用>
<赋值函数> -> <变量> <赋值或函数调用>
<赋值或函数调用> -> <自增减运算符> ;
<赋值或函数调用> -> = <右值> ;
<赋值或函数调用> -> += <右值> ;
<赋值或函数调用> -> -= <右值> ;
<赋值或函数调用> -> *= <右值> ;
<赋值或函数调用> -> /= <右值> ;
<赋值或函数调用> -> %= <右值> ;
<赋值或函数调用> -> ( <参数列表> ) ;
<参数列表> -> <参数> <参数闭包>
<参数闭包> -> , <参数> <参数闭包>
<参数闭包> -> $
<参数> -> <标识符>
<参数> -> <数字>
<参数> -> <字符串>
<字符串> -> string
<for循环> -> for <for循环块>
<for循环块> -> ( <赋值函数> <逻辑表达式> ; <一元表达式> ) <复合函数块>
<逻辑表达式> -> <表达式> <逻辑运算符> <表达式>
<逻辑运算符> -> <
<逻辑运算符> -> <=
<逻辑运算符> -> >
<逻辑运算符> -> >=
<逻辑运算符> -> <>
<逻辑运算符> -> ==
<while循环> -> while <while循环块>
<while循环块> -> ( <逻辑表达式> ) <复合函数块>
<条件语句> -> if <条件语句块>
<条件语句块> -> ( <逻辑表达式> ) <复合函数块> <否则语句>
<否则语句> -> else <复合函数块>
<否则语句> -> $
<函数返回> -> return <因式> ;
二、
实验所用的语法分析方法——LL1预测分析表法
支持根据输入的文法自动生成非终结符与终结符的first集、产生式的first集、非终结符的follow集、产生式的select集、预测分析表。
三、
程序结构
说明如下(实验二已经有的词法分析就不赘述了):
(一)在Global.h中加入了5个结构体类型,分别有:
1.
struct normalNode { //普通节点,用来组织成token链表,最后链表作为输入符号串用于语法分析过程中
string content; //内容
int type; //类型
string tokenStr; //以字符串形式表示的token
int addr; //入口地址,除去标识符以外的token入口地址都默认为-1
int line; //所在行数
normalNode *next; //下个节点
};
2.
struct identifierNode { //标识符节点,用来组织成标识符链表
string content; //内容
int addr; //入口地址,意思是所有同个标识符的入口地址将会一样,都是标识符第一次出现时的地址
int line; //所在行数
identifierNode *next; //下个节点
};
3.
struct errorNode { //错误节点,用来组织成错误链表
string content; //内容
int line; //所在行数
errorNode *next; //下个节点
};
4.
struct treeNode { //语法树节点
string content; //内容
int childNum; //孩子数目
treeNode* children[MAXCHILDREN];
treeNode(string s) { //构造函数
content = s;
childNum = 0;
}
treeNode() {
childNum = 0;
}
};
5.
//栈结构,实现长度自动增长缩小
struct myStack {
string *item = NULL;
int max; //能存的元素最大个数
int n; //已存的元素个数
myStack(int newMax) {
max = newMax;
item = new string[max];
n = 0;
}
void resize(int newMax) {
max = newMax;
string *temp = new string[newMax];
for (int i = 0; i < n; ++i) {
temp[i] = item[i];
}
delete[] item;
item = temp;
}
void push(string s) {
if (n == max) resize(max * 2);
item[n++] = s;
}
string top() {
return item[n - 1];
}
void pop() {
n--;
item[n] = '\0';
if (n > 0 && n == max / 4) resize(max / 2);
}
};
最后一个比较特殊,在结构体中增加了函数,实现栈结构的基本操作,并且该栈是动态增减的。
(二)头文件Parse.h声明了变量和函数如下:
//存放产生式的结构
struct production{
string noneTerminalSymbol; //非终结符
vector<string> generation; //该非终结符的产生式右部
};
extern set<string> terminalSymbols ; //终结符集
extern set<string> noneTerminalSymbols ; //非终结符集
extern string startToken ; //文法的开始符
extern string totalProductions[MAXNT] ; //存放文法文件的每一行
extern production productions[MAXNT] ; //将所有产生式存储为结构体。假定产生式"->"左右两边都有空格
extern map<string,set<string>> firstSet; //存有所有文法符号的first集合
extern map<int ,set<string>> productionFirstSet; //存有所有产生式的first集合
extern map<string,set<string>> followSet; //存有所有非终结符的follow集合
extern map<int,set<string>> selectSet; //存有所有产生式的select集合
extern map<string,map<string,string>> predictionTable; //预测分析表
extern myStack *analysisStack; //分析栈
extern int top; //分析栈的栈顶指针
可见,各种集合是由set数据结构进行存储,并且用map数据结构进行组织。
(三)源文件Parse.cpp实现了语法分析过程中的各主要函数。其中涉及的算法如下:
1.
//求所有文法符号的first集合
void buildFirstSet();
(1)初始化所有终结符的first集,为其本身。
(2)在do…while循环中用for循环对产生式右部每个元素进行判断,比如有产生式S->ABc,则先依次获得产生式右部每个元素的first集中的元素,也就是先获得A的first集,将A的first集元素除了空字之外都加到S的first集中。如果A的first集中没有空字,则结束求此产生式S的first集,否则继续读取,对B进行操作。如果for循环结束之后最后一个元素的first集仍有空字,则将空字也加入S的first集中。
(3)重复do…while,直到所有非终结符的first集不再改变。
2.
//求所有产生式的first集合
void buildProductionFirstSet();
(1)遍历产生式Xi右部,如S->ABc,先看first(A),将first(A)都加入first(Xi)即first(S->ABc)中,除了空字。
(2)如果当前符号(A)的first集中没有空字,则求该产生式的first集可以结束了,否则继续取之后符号的first集,即first(B)。
(3)如果遍历到产生式右部末尾,且最后一个符号的first集仍有空字,则将空字也加入产生式的first集中。
3.
//求所有非终结符的follow集合
void buildFollowSet() ;
(1)遍历所有产生式
(2)对于每条产生式x,如A->aBβα,遍历产生式右部,依次判断x[ j ]。如果x[ j ]是非终结符,即读到B,则求B的follow集。
(3)遍历B之后的文法符号,即βα。先将first(β)的非空元素加入follow(B)中。
(4)如果此时符号β的first集不包含空字,则退出遍历B之后的文法符号。否则继续遍历。
(5)如果读到产生式末尾,并且最后一个仍包含空字,则把follow(A)也加入follow(B)中。
(6)重复(2)到(5)的操作,如果产生式最后一个符号是非终结符,则该follow集将无法由上述步骤求出。因此直接将follow(A)加入该follow集中。
(7)若有非终结符的follow集改变了,则重复(1)到(6)的操作。
4.
//求所有产生式的select集合
void buildSelectSet() ;
遍历所有产生式,对于产生式A->α,若α不能推出空字,则select(A->α) = first(α)。如果α能推出空字,则select(A->α) = (first(α) - {$}) U follow(A)。
5.
//构建预测分析表
void buildPredictionTable();
若a ∈ select(A -> α),则把A -> α放入predictionTable[A,a]中。
6.
//正式用预测分析表进行语法分析
void analyse() ;
(1)构建分析栈,将normalNode链表作为输入串。在分析栈中依次压入结束符号#和开始符号,在输入串的末尾加上结束符号#,让当前指针指向normalNode链表的头结点(注意:头结点为空)。
(2)看分析栈栈顶,如果栈顶是非终结符,面临剩余输入串的首符号时,查看预测分析表中是否有对应的产生式。若有,则弹出分析栈栈顶,将产生式反向压入分析栈,若无对应的产生式,则表明用栈顶为左部向下推导时遇到了不该出现的符号,因此显示出错。如果栈顶是终结符,面临剩余输入串的首符号时,若两个符号相等,则弹出分析栈栈顶,同时将指针指向剩余输入串的下个结点。
(3)重复(2)操作。若最后分析栈栈顶是#,剩余输入串的首符号是#,则说明语法分析通过。
——————————————————分割线—————————————————————
过了几天后来看了下代码,在语法分析过程这里想了一会,才想明白当时的具体过程。为了防止以后再来看代码时又卡壳,觉得还是画个示意图比较好。拍照如下:(手画orz)
黑色部分表示分析初始时的情况,红色部分表示开始第1次分析时的的情况。
——————————————————分割线—————————————————————
(四)程序调试
编写测试代码test.cmm如下,涉及当前CMM语言的各个方面:
int main(int argc)
{
int i=5;
int sum=0; //这是单行注释
if(i>0) {
sum+=i;
i--;
}
real j=100.5;
// real k=50d; //这会出错
/*
这是多行
注释
*/
int array[] = {
1,2,3,4};
for(int i=0;i<10;i++) {
j += i;
}
while(j>0) {
test(j);
j--;
}
}
int test(int x) {
}
四、
运行结果如下:
(1)Set.txt文件存放中间输出,first集、follow集、select集、预测分析表:
————————————————————————文法非终结符如下——————————————————————————
<for循环>
<for循环块>
<while循环>
<while循环块>
<一元表达式>
<函数块>
<函数块闭包>
<函数定义或声明>
<函数定义或声明闭包>
<函数返回>
<前缀表达式>
<参数>
<参数列表>
<参数声明>
<参数闭包>
<变量>
<右值>
<后缀表达式>
<否则语句>
<因子>
<因式>
<因式递归>
<声明>
<声明语句>
<声明语句闭包>
<声明闭包>
<复合函数块>
<多个数据>
<字符串>
<数字>
<数字闭包>
<数组下标>
<条件语句>
<条件语句块>
<标识符>
<程序>
<类型>
<自增减运算符>
<表达式>
<赋值函数>
<赋值或函数调用>
<赋初值>
<逻辑表达式>
<逻辑运算符>
<项>
————————————————————————文法终结符如下————————————————————————
#
$
%
%=
(
)
*
*=
+
++
+=
,
-
--
-=
/
/=
;
<
<=
<>
=
==
>
>=
FLOAT_VALUE
ID
INT_VALUE
[
]
else
for
if
int
real
return
string
while
{
}
————————————————————————文法符号的first集如下————————————————————————
# : {#}
$ : {$}
% : {%}
%= : {%=}
( : {(}
) : {)}
* : {*}
*= : {*=}
+ : {+}
++ : {++}
+= : {+=}
, : {,}
- : {-}
-- : {--}
-= : {-=}
/ : {/}
/= : {/=}
; : {;}
< : {<}
<= : {<=}
<> : {
<>}
<for循环> : {for}
<for循环块> : {(}
<while循环> : {while}
<while循环块> : {(}
<一元表达式> : {++,--,ID}
<函数块> : {$,++,--,ID,for,if,int,real,return,while}
<函数块闭包> : {$,++,--,ID,for,if,int,real,return,while}
<函数定义或声明> : {int,real}
<函数定义或声明闭包> : {;,{}
<函数返回> : {return}
<前缀表达式> : {++,--}
<参数> : {FLOAT_VALUE,ID,INT_VALUE,string}
<参数列表> : {FLOAT_VALUE,ID,INT_VALUE,string}
<参数声明> : {$,int,real}
<参数闭包> : {$,,}
<变量> : {ID}
<右值> : {$,%,(,*,+,++,-,--,/,FLOAT_VALUE,ID,INT_VALUE,{}
<后缀表达式> : {ID}
<否则语句> : {$,else}
<因子> : {$,%,(,*,/,FLOAT_VALUE,ID,INT_VALUE}
<因式> : {$,(,FLOAT_VALUE,ID,INT_VALUE}
<因式递归> : {$,%,*,/}
<声明> : {int,real}
<声明语句> : {int,real}
<声明语句闭包> : {$,int,real}
<声明闭包> : {$,,}
<复合函数块> : {
{}
<多个数据> : {
FLOAT_VALUE,INT_VALUE}
<字符串> : {
string}
<数字> : {
FLOAT_VALUE,INT_VALUE}
<数字闭包> : {$,,}
<数组下标> : {$,[}
<条件语句> : {
if}
<条件语句块> : {(}
<标识符> : {
ID}
<程序> : {$,int,real}
<类型> : {
int,real}
<自增减运算符> : {++,--}
<表达式> : {$,%,(,*,+,++,-,--,/,FLOAT_VALUE,ID,INT_VALUE}
<赋值函数> : {++,--,ID,int,real}
<赋值或函数调用> : {%=,(,*=,++,+=,--,-=,/=,=}
<赋初值> : {$,=}
<逻辑表达式> : {%,(,*,+,++,-,--,/,<,<=,<>,==,>,>=,FLOAT_VALUE,ID,INT_VALUE}
<逻辑运算符> : {<,<=,<>,==,>,>=}
<项> : {$,+,-}
= : {=}
== : {==}
> : {>}
>= : {>=}
FLOAT_VALUE : {
FLOAT_VALUE}
ID : {
ID}
INT_VALUE : {
INT_VALUE}
[ : {[}
] : {]}
else : {
else}
for : {
for}
if : {
if}
int : {
int}
real : {
real}
return : {
return}
string : {
string}
while : {
while}
{ : {
{}
} : {}}
————————————————————————文法产生式的first集如下————————————————————————
<程序> -> <函数定义或声明> <程序> : {int,real}
<程序> -> $ : {$}
<函数定义或声明> -> <类型> <变量> ( <参数声明> ) <函数定义或声明闭包> : {int,real}
<函数定义或声明闭包> -> <复合函数块> : {
{}
<函数定义或声明闭包> -> ; : {;}
<类型> -> int : {
int}
<类型> -> real : {
real}
<变量> -> <标识符> <数组下标> : {
ID}
<标识符> -> ID : {
ID}
<数组下标> -> [ <因式> ] : {[}
<数组下标> -> $ : {$}
<因式> -> ( <表达式> ) : {(}
<因式> -> <变量> : {
ID}
<因式> -> <数字> : {
FLOAT_VALUE,INT_VALUE}
<因式> -> $ : {$}
<数字> -> INT_VALUE : {
INT_VALUE}
<数字> -> FLOAT_VALUE : {
FLOAT_VALUE}
<表达式> -> <一元表达式> : {++,--,ID}
<表达式> -> <因子> <项> : {$,%,(,*,+,-,/,FLOAT_VALUE,ID,INT_VALUE}
<一元表达式> -> <前缀表达式> : {++,--}
<一元表达式> -> <后缀表达式> : {
ID}
<前缀表达式> -> <自增减运算符> <变量> : {++,--}
<后缀表达式> -> <变量> <自增减运算符> : {
ID}
<自增减运算符> -> ++ : {++}
<自增减运算符> -> -- : {
--}
<因子> -> <因式> <因式递归> : {$,%,(,*,/,FLOAT_VALUE,ID,INT_VALUE}
<因式递归> -> * <因式> <因式递归> : {*}
<因式递归> -> / <因式> <因式递归> : {/}
<因式递归> -> % <因式> <因式递归> : {%}
<因式递归> -> $ : {$}
<项> -> + <因子> <项> : {+}
<项> -> - <因子> <项> : {
-}
<项> -> $ : {$}
<参数声明> -> <声明> <声明闭包> : {
int,real}
<参数声明> -> $ : {$}
<声明> -> <类型> <变量> <赋初值> : {
int,real}
<赋初值> -> = <右值> : {=}
<赋初值> -> $ : {$}
<右值> -> <表达式> : {$,%,(,*,+,++,-,--,/,FLOAT_VALUE,ID,INT_VALUE}
<右值> -> { <多个数据> } : {
{}
<多个数据> -> <数字> <数字闭包> : {
FLOAT_VALUE,INT_VALUE}
<数字闭包> -> , <数字> <数字闭包> : {,}
<数字闭包> -> $ : {$}
<声明闭包> -> , <声明> <声明闭包> : {,}
<声明闭包> -> $ : {$}
<复合函数块> -> { <函数块> } : {
{}
<函数块> -> <声明语句闭包> <函数块闭包> : {$,++,--,ID,for,if,int,real,return,while}
<声明语句闭包> -> <声明语句> <声明语句闭包> : {
int,real}
<声明语句闭包> -> $ : {$}
<声明语句> -> <声明> ; : {
int,real}
<函数块闭包> -> <赋值函数> <函数块> : {++,--,ID,int,real}
<函数块闭包> -> <for循环> <函数块> : {
for}
<函数块闭包> -> <while循环> <函数块> : {
while}
<函数块闭包> -> <条件语句> <函数块> : {
if}
<函数块闭包> -> <函数返回> <函数块> : {
return}
<函数块闭包> -> $ : {$}
<赋值函数> -> <自增减运算符> <变量> ; : {++,--}
<赋值函数> -> <类型> <变量> <赋值或函数调用> : {
int,real}
<赋值函数> -> <变量> <赋值或函数调用> : {
ID}
<赋值或函数调用> -> <自增减运算符> ; : {++,--}
<赋值或函数调用> -> = <右值> ; : {=}
<赋值或函数调用> -> += <右值> ; : {+=}
<赋值或函数调用> -> -= <右值> ; : {
-=}
<赋值或函数调用> -> *= <右值> ; : {*=}
<赋值或函数调用> -> /= <右值> ; : {/=}
<赋值或函数调用> -> %= <右值> ; : {%=}
<赋值或函数调用> -> ( <参数列表> ) ; : {(}
<参数列表> -> <参数> <参数闭包> : {
FLOAT_VALUE,ID,INT_VALUE,string}
<参数闭包> -> , <参数> <参数闭包> : {,}
<参数闭包> -> $ : {$}
<参数> -> <标识符> : {
ID}
<参数> -> <数字> : {
FLOAT_VALUE,INT_VALUE}
<参数> -> <字符串> : {
string}
<字符串> -> string : {
string}
<for循环> -> for <for循环块> : {
for}
<for循环块> -> ( <赋值函数> <逻辑表达式> ; <一元表达式> ) <复合函数块> : {(}
<逻辑表达式> -> <表达式> <逻辑运算符> <表达式> : {%,(,*,+,++,-,--,/,<,<=,<>,==,>,>=,FLOAT_VALUE,ID,INT_VALUE}
<逻辑运算符> -> < : {<}
<逻辑运算符> -> <= : {<=}
<逻辑运算符> -> > : {>}
<逻辑运算符> -> >= : {>=}
<逻辑运算符> -> <> : {<>}
<逻辑运算符> -> == : {==}
<while循环> -> while <while循环块> : {
while}
<while循环块> -> ( <逻辑表达式> ) <复合函数块> : {(}
<条件语句> -> if <条件语句块> : {
if}
<条件语句块> -> ( <逻辑表达式> ) <复合函数块> <否则语句> : {(}
<否则语句> -> else <复合函数块> : {
else}
<否则语句> -> $ : {$}
<函数返回> -> return <因式> ; : {
return}
————————————————————————非终结符的follow集如下————————————————————————
<for循环> : {++,--,ID,for,if,int,real,return,while,}}
<for循环块> : {++,--,ID,for,if,int,real,return,while,}}
<while循环> : {++,--,ID,for,if,int,real,return,while,}}
<while循环块> : {++,--,ID,for,if,int,real,return,while,}}
<一元表达式> : {),,,;,<,<=,<>,==,>,>=}
<函数块> : {}}
<函数块闭包> : {}}
<函数定义或声明> : {#,int,real}
<函数定义或声明闭包> : {#,int,real}
<函数返回> : {++,--,ID,for,if,int,real,return,while,}}
<前缀表达式> : {),,,;,<,<=,<>,==,>,>=}
<参数> : {),,}
<参数列表> : {)}
<参数声明> : {)}
<参数闭包> : {)}
<变量> : {%,%=,(,),*,*=,+,++,+=,,,-,--,-=,/,/=,;,<,<=,<>,=,==,>,>=,]}
<右值> : {),,,;}
<后缀表达式> : {),,,;,<,<=,<>,==,>,>=}
<否则语句> : {++,--,ID,for,if,int,real,return,while,}}
<因子> : {),+,,,-,;,<,<=,<>,==,>,>=}
<因式> : {%,),*,+,,,-,/,;,<,<=,<>,==,>,>=,]}
<因式递归> : {),+,,,-,;,<,<=,<>,==,>,>=}
<声明> : {),,,;}
<声明语句> : {++,--,ID,for,if,int,real,return,while,}}
<声明语句闭包> : {++,--,ID,for,if,int,real,return,while,}}
<声明闭包> : {)}
<复合函数块> : {#,++,--,ID,else,for,if,int,real,return,while,}}
<多个数据> : {}}
<字符串> : {),,}
<数字> : {%,),*,+,,,-,/,;,<,<=,<>,==,>,>=,],}}
<数字闭包> : {}}
<数组下标> : {%,%=,(,),*,*=,+,++,+=,,,-,--,-=,/,/=,;,<,<=,<>,=,==,>,>=,]}
<条件语句> : {++,--,ID,for,if,int,real,return,while,}}
<条件语句块> : {++,--,ID,for,if,int,real,return,while,}}
<标识符> : {%,%=,(,),*,*=,+,++,+=,,,-,--,-=,/,/=,;,<,<=,<>,=,==,>,>=,[,]}
<程序> : {#}
<类型> : {ID}
<自增减运算符> : {),,,;,<,<=,<>,==,>,>=,ID}
<表达式> : {),,,;,<,<=,<>,==,>,>=}
<赋值函数> : {%,(,*,+,++,-,--,/,<,<=,<>,==,>,>=,FLOAT_VALUE,ID,INT_VALUE,for,if,int,real,return,while,}}
<赋值或函数调用> : {%,(,*,+,++,-,--,/,<,<=,<>,==,>,>=,FLOAT_VALUE,ID,INT_VALUE,for,if,int,real,return,while,}}
<赋初值> : {),,,;}
<逻辑表达式> : {),;}
<逻辑运算符> : {%,(,),*,+,++,-,--,/,;,FLOAT_VALUE,ID,INT_VALUE}
<项> : {),,,;,<,<=,<>,==,>,>=}
————————————————————————产生式的select集如下————————————————————————
<程序> -> <函数定义或声明> <程序> : {int,real}
<程序> -> $ : {#}
<函数定义或声明> -> <类型> <变量> ( <参数声明> ) <函数定义或声明闭包> : {int,real}
<函数定义或声明闭包> -> <复合函数块> : {
{}
<函数定义或声明闭包> -> ; : {;}
<类型> -> int : {
int}
<类型> -> real : {
real}
<变量> -> <标识符> <数组下标> : {
ID}
<标识符> -> ID : {
ID}
<数组下标> -> [ <因式> ] : {[}
<数组下标> -> $ : {%,%=,(,),*,*=,+,++,+=,,,-,--,-=,/,/=,;,<,<=,<>,=,==,>,>=,]}
<因式> -> ( <表达式> ) : {(}
<因式> -> <变量> : {
ID}
<因式> -> <数字> : {
FLOAT_VALUE,INT_VALUE}
<因式> -> $ : {%,),*,+,,,-,/,;,<,<=,<>,==,>,>=,]}
<数字> -> INT_VALUE : {
INT_VALUE}
<数字> -> FLOAT_VALUE : {
FLOAT_VALUE}
<表达式> -> <一元表达式> : {++,--,ID}
<表达式> -> <因子> <项> : {%,(,),*,+,,,-,/,;,<,<=,<>,==,>,>=,FLOAT_VALUE,ID,INT_VALUE}
<一元表达式> -> <前缀表达式> : {++,--}
<一元表达式> -> <后缀表达式> : {
ID}
<前缀表达式> -> <自增减运算符> <变量> : {++,--}
<后缀表达式> -> <变量> <自增减运算符> : {
ID}
<自增减运算符> -> ++ : {++}
<自增减运算符> -> -- : {
--}
<因子> -> <因式> <因式递归> : {%,(,),*,+,,,-,/,;,<,<=,<>,==,>,>=,FLOAT_VALUE,ID,INT_VALUE}
<因式递归> -> * <因式> <因式递归> : {*}
<因式递归> -> / <因式> <因式递归> : {/}
<因式递归> -> % <因式> <因式递归> : {%}
<因式递归> -> $ : {),+,,,-,;,<,<=,<>,==,>,>=}
<项> -> + <因子> <项> : {+}
<项> -> - <因子> <项> : {
-}
<项> -> $ : {),,,;,<,<=,<>,==,>,>=}
<参数声明> -> <声明> <声明闭包> : {
int,real}
<参数声明> -> $ : {)}
<声明> -> <类型> <变量> <赋初值> : {
int,real}
<赋初值> -> = <右值> : {=}
<赋初值> -> $ : {),,,;}
<右值> -> <表达式> : {%,(,),*,+,++,,,-,--,/,;,FLOAT_VALUE,ID,INT_VALUE}
<右值> -> { <多个数据> } : {
{}
<多个数据> -> <数字> <数字闭包> : {
FLOAT_VALUE,INT_VALUE}
<数字闭包> -> , <数字> <数字闭包> : {,}
<数字闭包> -> $ : {}}
<声明闭包> -> , <声明> <声明闭包> : {,}
<声明闭包> -> $ : {)}
<复合函数块> -> { <函数块> } : {
{}
<函数块> -> <声明语句闭包> <函数块闭包> : {++,--,ID,for,if,int,real,return,while,}}
<声明语句闭包> -> <声明语句> <声明语句闭包> : {int,real}
<声明语句闭包> -> $ : {++,--,ID,for,if,int,real,return,while,}}
<声明语句> -> <声明> ; : {int,real}
<函数块闭包> -> <赋值函数> <函数块> : {++,--,ID,int,real}
<函数块闭包> -> <for循环> <函数块> : {for}
<函数块闭包> -> <while循环> <函数块> : {while}
<函数块闭包> -> <条件语句> <函数块> : {if}
<函数块闭包> -> <函数返回> <函数块> : {return}
<函数块闭包> -> $ : {}}
<赋值函数> -> <自增减运算符> <