0%

语法分析器

有点晕,先记录一下。

概述

PL/0语言的语法可以用以下上下文无关文法描述:

<程序>→<分程序>.
<分程序>→ [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>
<常量说明部分> → CONST<常量定义>{ ,<常量定义>};
<常量定义> → <标识符>=<无符号整数>
<无符号整数> → <数字>{<数字>}
<变量说明部分> → VAR<标识符>{ ,<标识符>};
<标识符> → <字母>{<字母>|<数字>}
<过程说明部分> → <过程首部><分程序>;{<过程说明部分>}
<过程首部> → PROCEDURE <标识符>;
<语句> → <赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>|<空语句>
<赋值语句> → <标识符>:=<表达式>
<复合语句> → BEGIN<语句>{ ;<语句>} END
<条件> → <表达式><关系运算符><表达式>|ODD<表达式>
<表达式> → [+|-]<项>{<加减运算符><项>}
<项> → <因子>{<乘除运算符><因子>}
<因子> → <标识符>|<无符号整数>|(<表达式>)
<加减运算符> → +|-
<乘除运算符> → *|/
<关系运算符> → =|#|<|<=|>|>=
<条件语句> → IF<条件>THEN<语句>
<过程调用语句> → CALL<标识符>
<当型循环语句> → WHILE<条件>DO<语句>
<读语句> → READ(<标识符>{ ,<标识符>})
<写语句> → WRITE(<标识符>{,<标识符>})
<字母> → A|B|C…X|Y|Z
<数字> → 0|1|27|8|9
<空语句> → epsilon

原文描述的这个,感觉很乱……

整理

<程序>→<分程序>.

这是一整个程序的大体思路,然后接下来慢慢细分(注意文末这个 . )。

声明

<分程序>→[<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>

一个分程序可以分出:常量、变量、过程,后面接的都是句子。

<常量说明部分> → CONST<常量定义>{ ,<常量定义>};
<常量定义> → <标识符>=<无符号整数>
<无符号整数> → <数字>{<数字>}
<变量说明部分> → VAR<标识符>{ ,<标识符>};
<标识符> → <字母>{<字母>|<数字>}
<过程说明部分> → <过程首部><分程序>;{<过程说明部分>}
<过程首部> → PROCEDURE <标识符>;

写的抽象复杂,其实也就如下的形式(其中 i 为标识符 identifier (由字母、数字组成),num 为无符号整数代表的数字):

常量

CONST i = num;
CONST i1 = num1, i2 = num2, i3 = num3, ..., i_n = numn;

CONST 可定义一个或多个常量,其中每部分都是 i = num 的形式( , 隔开),以 ; 结尾。

变量

VAR i;
VAR i1, i2, i3, ..., i_n;

和常量差不多,注意定义变量的时候不会进行赋值。

过程

PROCEDURE i;

其中过程可以多层嵌套,但最大为3层:

PROCEDURE i1;
PROCEDURE i2;
PROCEDURE i1;
PROCEDURE i2;
PROCEDURE i3;

语句

接下来是最麻烦的部分,声明好了之后就需要分析语句。

<语句> → <赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>|<空语句>

有8种语句。用 syntax 代表语句。

赋值语句

<赋值语句> → <标识符>:=<表达式>
<表达式> → [+|-]<项>{<加减运算符><项>} // <加减运算符> → +|-
<项> → <因子>{<乘除运算符><因子>} // <乘除运算符> → *|/
<因子> → <标识符>|<无符号整数>|(<表达式>)

循环嵌套,咋一看很乱,慢慢整理:

i := expression

这个地方最好用 expression 代表一下表达式,不如很乱。表达式格式如下:

+i			-i			i
+num -num num
即以上总结为[+|-]i|num
[+|-] i|num {+|-|*|/ i|num}

就像这样的可以无限套娃,注意由乘除衔接的成为因子,用加减衔接的成为项。

综上,赋值语句表示为 i := 我们熟悉的只含加减乘除的那种式子

条件语句/当型循环语句

<条件语句> → IF<条件>THEN<语句>
<条件> → <表达式><关系运算符><表达式>|ODD<表达式>
<关系运算符> → =|#|<|<=|>|>=
<当型循环语句> → WHILE<条件>DO<语句>

关系运算符的 # 代表 != 。用 condition 代表条件:

IF condition THEN syntax;
WHILE condition DO syntax;

其中条件参考条件语句:

expression1 = | # | < | <= | > | >= expression2
举个例子,形如 i = 1 i + i < 9 i * i >= 10

过程调用语句

<过程调用语句> → CALL<标识符>

比较简单,也就是

CALL i

读语句/写语句

<读语句> → READ(<标识符>{ ,<标识符>})
<写语句> → WRITE(<标识符>{,<标识符>})

也比较简单:

READ(i)
READ(i1, i2, ..., i_n)
WRITE(i)
WRITE(i1, i2, ..., i_n)

复合语句

<复合语句> → BEGIN<语句>{ ;<语句>} END

也就是说,形如:

BEGIN
syntax;
END

也可多个语句:

BEGIN
syntax1;
syntax2;
....
syntax_n;
END

分号大概是这样没错。

空语句

<空语句> → epsilon

推出空,也就先放着吧。