实验三:CMM语言语法分析

注意:
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}
<函数块闭包> -> $ : {}}
<赋值函数> -> <自增减运算符> <
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值