我们的编译原理作业
老师让写一个calculator,第一次写编译程序可能里面有不少冗余和低级处理,但是也push出来和大家共勉。
环境
我使用的是VS2019,用的c语言来做的。
目标
计算器接受四则运算表达式为输入(如下所示)。如果表达式语法正确,则输出计算结果,否则报错,指出错误位置及原因。
Input 1:
float a;
int b;
a = (10.44*356+1.28) / 2 + 1024 * 1.6;
b = a * 2 – a/2;
write(b);
write(a).
Output 1:
5246
3497.36
Input 2:
float a;
int b;
a = (10.44*356+1.28) / 2 + 1024 * 1.6;
b = a * 2 – c/2;
write(b).
Output 2:
Error(line 4): undefined identifier .
1)支持浮点数和整数两种类型,浮点数可以转换成整数;整数不可以转换成浮点数;
2)每个语句需要以“;”结束,以“.”表示全部输入的结束
3)变量需要先声明再使用;
4)变量名可以是由数字和字母组成,但首字符必须是字母。
5)每个表达式中使用的变量需要在之前已经有赋值。
6)输出语句使用write(a),输出并换行,其中a为int类型或者float类型的变量名。
我的编程思路
首先scan函数和cal函数最为关键,也最能体现我的主体思想。
定义了变量的struct结构体,建立了变量的双链表用于存储和查找变量,cal函数返回的就是变量链表的头部指针。
当然还有查找变量、增加变量的函数等。都是对于这个双链表的操作。
对变量的定义,我使用了IDENTIFIER_F 和 IDENTIFIER_I 分别表示我scan到了的token是标识符。
然后当我发现这是一个使用标识符的定义语句时,在case IDENDTIFIER_X 中检查下一个token ,如果是= 就是进入赋值操作,
对变量链表进行相应修改。
而对于赋值语句,我添加枚举类型VAL ,当我检查到token是变量的时候,进入case VAL:,为了区分这个变量是在运算中,
还是一个类似a=b+1 的赋值语句我就在检查下一个token是不是=。(那这个时候可能会有疑问,怎么区分float a=1;和a=1;其实
第一种情况由于已经检测到了标识符所以不会进入case VAL;在case IDENTIFITER_F就会完成创建变量的操作)如果发现下一个,
token是=,就将赋值标识符设置为1,只用当is_giveValue=1的时候才会进入到cal中的计算后缀表达式的部分。而如果token不是=,
那么就说明这个变量是在计算表达式中的,代表一个数值,我就在双链表中寻找这个变量名,如果没找到报错,找到的话就创建一
个Token结构,并将其push进post堆栈,直接完成变量到数值的转换。
注:对于报错则使用了fget按行读取以及全局变量LINE和记录当前line内容的全局BUF。
我的文法定义
program 程序
statement 声明
identifier 类型定义
value 变量
Assignment statement 赋值语句
Normal statement 一般语句
Computation statement 计算语句
Function statement 功能语句
Write statement 输出语句
num 数字常量
digital_I 整数
digital_F 浮点数
Reserved word 保留字
calulation define{ (对计算器计算语句的定义 level代表优先级,数字越大意味着优先级越高)
level_1 代表加减
level_2 代表乘除
level_3 代表负号
level_4 数字或括号
}
相关正则定义:
Letter [a-z,A-Z]
Digital [0-9]
Underline ['_']
specific_num {Digital}((.{Digital}+)|{Digital}*)
<program> -> <statement> | <statement> (<Normal statement> | Ø | Function statement) <program>
<statement> -> <identifier> <value> | <identifier> <Assignment statement>
<Normal statement> -> <value> <'='> <Computation statement>
<Computation statement> -> <level_1>
<level_1> -> <level_1> <'+'> <level_2> | <level_1> <'-'> <level_2> | <level_2>
<level_2> -> <level_2> <'*'> <level_3> | <level_2> <'/'> <level_3> | <level_3>
<level_3> -> <'-'><level_4> | <level_4>
<level_4> -> <'('> <level_1> <')'> | <num>
<Function statement> -> <Write statement> | <Other statement> /*(目前其他功能语句为空) */
<Write statement> -> <Reserved word> <'('> <value> <')'>
<Reserved word> -> <'write'>
<Assignment statement> -> <value> <'='> <num>
<value> -> (Letter)(Letter)*(Digital)*Underline*(Digital)*(Letter)*Underline*(Digital)*(Letter)*
<num> -> <digital_F> | <digital_I>
源代码
我已经上传到了gitee
点击查看源代码