基于编译原理的计算器设计与实现
汇编语言课程设计四则运算计算器..【范本模板】

微机原理实验报告汇编语言课程设计报告( 2012 —- 2013 年度第1 学期)实验名称:实现加减乘除四则运算的计算器专业生物医学工程学生姓名周炳威班级B100904学号B10090406指导教师乐洋实现加减乘除四则运算的计算器1 实验目的深化学习的汇编语言课程基本知识,进一步掌握汇编语言程序设计方法,提高分析问题、解决问题的综合应用能力。
通过使用汇编语言设计实现简单计算器,以此进一步了解和掌握对数据存储,寄存器的使用,加减乘除相关指令以及模块的调用等汇编语言知识的有效运用2 实验内容课题名称:实现加减乘除四则运算的计算器主要功能:实现一个简单的计算器,要求:编写一个程序,每运行一次可执行程序,可以实现加减乘除四则运算。
计算器是最简单的计算工具,简单计算器具有加、减、乘、除四项运算功能。
3 实现方法本次汇编语言课程设计的最终目的是要实现一个简单计算器,要求编写一个程序,每运行一次可执行程序,可以实现数的加减乘除四则运算。
由自己调用中断输入到屏幕上并要用程序存储起来的数,然后才能对这两个数进行运算,而且做的是加法运算、减法运算乘法运算还是除法运算也未可知,为此我们还要判断用户所输入的运算是四则运算中的哪一个运算。
此外,运算过程中的进位或是借位,选择用什么样的方式进行输出,如何实现清屏等也是要解决的问题。
第一步,用INT 21H的1号功能调用来进行输入.利用1号功能调用来输入,即把单个字符一个个的输入并存储到一个数据区里。
我们要做的是两个数的运算,先认定输入的格式为1234+5678=或者1111*2222=,当然如果输入不是这样的格式计算出来的结果就不一定是我们想要的结果了.在存储的时候也是有选择的存储,当输入的并非格式里所要求的字符时则报错.第二步,设计程序进行判断所输入的算式是做加法运算、减法运算、乘法运算还是除法运算,即判断输入的运算符是‘+'号、‘—'号、‘*’号、‘/’号中的哪一个,因为输入的格式固定了,所以只需要把存进数据区的第三个字符拿来与加减乘除四个运算符号进行比较,和哪一个运算符号一样就调用相对应的运算模块进行计算。
汇编语言课程设计报告——实现加减乘除四则运算的计算器讲解

汇编语言课程设计报告(2011 -- 2012年度第2学期)实现加减乘除四则运算的计算器专业_____________ 计算机科学与技术__________学生姓名____________________________________班级_______________________________________学号_______________________________________指导教师____________________________________完成日期___________________________________目录目录 (2)1概述 (1)1.1设计目的 (1)1.2设计内容 (1)2系统需求分析 (1)2.1 系统目标 (1)2.2主体功能 (1)2.3开发环境 (1)3系统概要设计 (2)3.1系统的功能模块划分 (2)3.2系统流程图 (3)4系统详细设计 (3)5测试 (4)5.1测试方案 (4)5.2测试结果 (4)6小结 (5)参考文献 (6)附录 (7)附录源程序清单 (7)实现加减乘除四则运算的计算器1.1设计目的本课程设计是在学完教学大纲规定的全部内容、完成所有实践环节的基础上, 旨在深化学生学习的汇编语言课程基本知识,进一步掌握汇编语言程序设计方法, 提高分析问题、解决问题的综合应用能力。
1.2设计内容能实现加、减、乘、除的计算;该程序接受的是16进制数;执行时,需要在文件名后直接跟上计算表达式,如在命令提示符下执行结果如下:c:\tasm>js 3+252系统需求分析2.1系统目标本次汇编语言课程设计的最终目的是要实现一个简单加减乘除四则运算的计算器,要求编写一个程序,每运行一次可执行程序,可以实现数的加减乘除四则运算。
比如,十进制数的加减乘除四则运算。
我们曾经学习过两个具体数字进行加减法运算,但是对于简单计算器用汇编语言实现难点在于这两个要做运算的数是未知的,是由自己调用中断输入到屏幕上并要用程序存储起来的数,然后才能对这两个数进行运算,而且做的是加法运算、减法运算乘法运算还是除法运算也未可知,为此我们还要判断用户所输入的运算是四则运算中的哪一个运算。
Go编译原理实现计算器(测试驱动讲解)

Go编译原理实现计算器(测试驱动讲解)本⽂不需要你掌握任何编译原理的知识。
只需要看懂简单的golang语⾔即可,完整的代码⽰例在, 代码是从这本书抽取了简单的部分出来, 如果需要进⼀步了解,请详阅此书.听到编译原理,就觉得很⾼⼤上。
记得上⼤学时,这门课要记忆⼀些BNF,LEX,AST,CFG这些有的没的。
⼀个听不懂,⼆个没兴趣。
随着使⽤了⼏门语⾔之后,也尝试⽤编译原理的基本知识写过⼀个sql转es的⼯具之后。
发现其实了解⼀点点编译原理的知识,能够提⾼我们的⽣产效率,做出⼀些很酷的⼩⼯具来。
本⽂将⽤golang和编译原理的基本技术实现⼀个计算器。
虽然功能简单,⽹上也有很多⼈做过类似事情,但这篇博客会有三个优点:我暂时没有找到有⼈⽤golang写我会⽤最直⽩的语⾔去描述我们要做什么,这样当你阅读的时候,会发现该步骤和书中哪⼀步是对应的,帮助你更好的理解编译原理的知识。
我会⽤测试驱动整个博客和代码,会让⼤家看到如何慢慢得演化出这个计算器得解释器。
就像⼩说中⼈物的⿊化有⼀个发酵的过程才会好看,我希望在本⽂中能够让读者看到⼀个解释器编写发酵的过程。
⽬标整体会实现⼀个函数,输⼊⼀个String, 输出⼀个int64。
// calc.gofunc calc(input string) int64 {}⽽我们的终极⽬标是能够让我们的calc的⽅法能够通过以下的测试// calc_test.gofunc TestFinal(t *testing.T) {tests := []struct{input stringexpected int64}{{"5", 5},{"10", 10},{"-5", -5},{"-10", -10},{"5 + 5 + 5 + 5 - 10", 10},{"2 * 2 * 2 * 2 * 2", 32},{"-50 + 100 + -50", 0},{"5 * 2 + 10", 20},{"5 + 2 * 10", 25},{"20 + 2 * -10", 0},{"50 / 2 * 2 + 10", 60},{"2 * (5 + 10)", 30},{"3 * 3 * 3 + 10", 37},{"3 * (3 * 3) + 10", 37},{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},}for _, tt := range tests{res := Calc(tt.input)if res != tt.expected{t.Errorf("Wrong answer, got=%d, want=%d", res, tt.expected)}}}我们运⾏这个测试,毫⽆疑问会失败。
汇编语言课程设计报告实现加减乘除四则运算的计算器

汇编语言课程设计报告实现加减乘除四则运算的计算器实现加减乘除四则运算的计算器目录1 概述 (1)1.1 课程设计目的 (1)1.2 课程设计内容 (1)2 系统需求分析 (1)2.1 系统目标 (1)2.2 主体功能 (2)3 系统概要设计 (2)3.1 系统的功能模块划分 (2)3.2 系统流程图 (3)4系统详细设计 (4)5 测试 (5)5.1 正确输出 (5)5.2 实际输出 (6)6 小结 (7)参考文献 (8)附录 (9)附录1 源程序清单 (9)汇编语言课程设计报告(2011)实现加减乘除四则运算计算器的设计1 概述1.1 课程设计目的运用汇编语言,实现简单计算器的一般功能.通过该程序设计,让我们熟悉并掌握DOS系统功能调方法用及BIOS系统功能调用方法,同时在程序设计过程中熟悉并掌握各种指令的应用,知道编程的具体流程,以及掌握DEBUG的一系列的功能执行命令,及用它进行调试,运行功能。
汇编语言是计算机能够提供给用户使用的最快而又最有效的语言,也是能够利用计算机所有硬件特性并能直接控制硬件的唯一语言。
由于汇编语言如此的接近计算机硬件,因此,它可以最大限度地发挥计算机硬件的性能。
由此可见汇编语言的重要性,学好这门课程,同样可为相关的专业打下基础。
汇编语言程序设计课程设计是在教学实践基础上进行的一次试验,也是对该课程所学理论知识的深化和提高。
因此,要求学生能综合应用所学知识,设计和制造出具有具有一定功能的应用系统,并且在实验的基本技能方面进行了一次全面的训练。
此外,它还可以培养学生综合运用所学知识独立完成汇编程序课题的能力,使学生能够较全面的巩固和应用课堂上所学的基本理论和程序设计方法,能够较熟练地完成汇编语言程序的设计和调试。
它同样可以提高学生运用理论去处理实际问题的能力和独立思考的能力,使学生的编程思想和编程能力有所提高,最终达到熟练地掌握编写汇编源程序的基本方法的目的。
1.2 课程设计内容设计一个能实现加减乘除取余计算的程序。
词法分析器-计算器-设计与实现实验报告汇总

辅导教师张静成绩else if(choice2(rz[st])==1)st=number(st);else if(rz[st]==’/’)st=anotation(st);else st=other(st);return st;}测试结果:8、心得通过本次的实验,使我真正的了解词法分析器的实现过程,让我更加深刻领悟词法分析器的实现原理.虽然在本次实验中遇到了各种各样的困难和错误,但在同学们的帮助下我都一一克服了,使得词法分析器能够正确的识别相应的词法和表达式。
在做实验的过程中,总是会忽略各种细节,从而导致经常修改一些很小的低级错误才能使程序正常运行,不仅浪费时间,还影响对其他地方的修改,并且在很多步骤处理上,方法不正确。
使结果不能符合要求,深刻体会到了自己在编程方面与别人的差距,在今后的学习中,我会注意改正自己在这方面的缺点,促使自己的编程水平不断进步.编译原理是一门专业学科,对于辅导教师张静成绩实验日期实验时间1实验名称计算器的设计与实现2、实验目的掌握自上而下语法分析方法、自下而上语法分析方法3、实验要求(1)实验内容设计及实现计算表达式的计算器。
表达式中可包含+、—、*、/、(、)等运算符。
(2)实验要求:对已给的一个二元式形式表达式,能够检查有无语法错误。
并指定出错位置。
将表达式的语法树输出(或将语法分析过程输出)。
4、实验原理根据算符优先分析思想实现语法分析程序。
5、实验步骤(1)根据文法构造语法分析表。
(2)编写总控程序实现语法分析。
6、算符优先分析表及语法分析程序算符优先分析表:case '(': /*当是的时候将此括号存入栈op*/op.top++;op。
data[op。
top]=ch;break;case ')’:while(op。
data[op.top] != ’(’) /*括号内的转换优先级最高故先提取表达式*/{exp[t]=op.data[op。
java 计算器 编译原理

java 计算器编译原理下面是一个简单的Java计算器的示例代码:```javaimport java.util.Scanner;public class Calculator {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入第一个操作数:");double operand1 = scanner.nextDouble();System.out.println("请输入运算符(+、-、*、/):"); String operator = scanner.next();System.out.println("请输入第二个操作数:");double operand2 = scanner.nextDouble();double result = 0;switch (operator) {case "+":result = operand1 + operand2;break;case "-":result = operand1 - operand2;break;case "*":result = operand1 * operand2;break;case "/":if (operand2 != 0) {result = operand1 / operand2;} else {System.out.println("错误:除数不能为0!");return;}break;default:System.out.println("错误:无效的运算符!");return;}System.out.println("计算结果为:" + result);}}```这个计算器程序首先从用户输入中获取第一个操作数、运算符和第二个操作数。
(完整word版)计算器的设计与实现 编译原理实验报告 (2)(word文档良心出品)

实验报告
专业软件工程
课程名称编译原理
学号
姓名
辅导教师张静成绩
实验日期
2015.5.19
实验时间
14:00~18:00
1实验名称计算器的设计与实现
2、实验目的
掌握自上而下语法分析方法、自下而上语法分析方法
3、实验要求
(1)实验内容
设计及实现计算表达式的计算器。
表达式中可包含+、-、*、/、(、)等运算符。
}op;
char ch;
int i = 0,t = 0;
op.top = -1;
ch = str[i];
i++;
while(ch != '\0')
{
switch(ch)
{
case '(':
op.top++;op.data[op.top]=ch;
break;
case ')':
while(op.data[op.top] != '(')
scanf("%c",&ch);
if(ch=='Y' || ch=='y')
{
gets(str);
}
else
{
break;
}
}
//system("pause");
return 0;
}
7、测试及结果
1、加减法运算
2、乘除法运算
3、带‘(’‘)’运算
4、四则运算
5、容错处理
8、心得
本次课程设计是实现一个简易的计算器,这次课程设计采用逆波兰式的知识,这可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。本次设计使我进一步端正了我的学习态度,学会了实事求是,对自己要严格要求。我觉得动手做设计之前,头脑里必须清楚该怎么做,这一点是很重要的。就目前来说,我的动手能力虽然差一点,但我想,通过我的不懈努力,在这方面,我总会得到提高。在此次的课程设计中我最大的体会就是进一步认识到了理论联系实践的重要性。总而言之,此次课程设计让我学到了好多平时在课堂上学不到的东西,增加了我的知识运用能力,增强我的实际操作能力。我相信经过实践后的学习我可以将编译原理这门课程掌握的更好。
编译原理-可编程计算器

郑州大学软件学院可编程计算器(项目报告)专业:计算机辅助设计专业院(系):软件学院学生姓名:古双军学号:20097720219 学生姓名:孔德汉学号:20097720225 学生姓名:孟晓帆学号:20097720240 学生姓名:周干学号:20097720267 完成时间:2012年6月18日年月日1、编译器的功能支持数值运算、逻辑运算和字符串运算,不区分大小写。
其中优先级定义+ -* / % mod> >= < <= = == <> !=& && | || and or not xor^sin cos min max left right abs if round pi可实现自顶向下的词法运算。
1)词法分析TokenKeywordFactory:用于处理关键字TokenSymbolFactory:用于处理运算符TokenStringFactory:用于处理字符串TokenNumberFactory:用于处理数字这里的处理过程是1.取字符“1”,转到TokenNumberFactory,把分析取到的字符串“123.3”转换为TokenNumber 并存到TokenList中2.取字符“*”,转到TokenSymbolFactory,把“*”转换成TokenMultiply并存到TokenList 中3.取字符“2”,转到TokenNumberFactory,把分析取到的字符串“2”转换为TokenNumber 并存到TokenList中4.取字符“- ”,转到TokenSymbolFactory,把“-”转换成TokenMinus并存到TokenList中5.取字符“( ”,转到TokenSymbolFactory,把“(”转换成TokenLeftBracket并存到TokenList 中6.取字符“2”,转到TokenNumberFactory,把分析取到的字符串“24”转换为TokenNumber 并存到TokenList中7.取字符“+”,转到TokenSymbolFactory,把“+”转换成TokenPlus并存到TokenList中8.取字符“3”,转到TokenNumberFactory,把分析取到的字符串“34”转换为TokenNumber 并存到TokenList中9.取字符“) ”,转到TokenSymbolFactory,把“)”转换成TokenRightBracket并存到TokenList 中2)语法分析1.列表分析状态:TokenValue(3)TokenMultiplayTokenValue(7)…...堆栈分析:当前堆栈为空,将当前分析的TokenRecord 压栈。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于编译原理的计算器设计与实现首先看一下这个计算器的功能:CALC> set a = 1; b = 2CALC> set c = 3CALC> calc (10 + pow(b, c)) * sqrt(4) - 135.0CALC> exit如上所示,这个计算器的功能非常简单:1.用set命令设置上下文中的变量。
2.用calc命令计算一个表达式的值。
3.用exit命令退出计算器。
我们把编译的重点放在calc命令后面的计算表达式的解析,其它的部分我们可以简单处理(如set命令可以这样简单处理:先按分号分隔得到多个赋值处理,再按等号分隔就可以在上下文中设置变量了,并不需要复杂的编译过程)。
如上的演示例子中,我们使用编译技术处理的部分是(10 + pow(b, c)) * sqrt(4) - 1,其它部分我们只使用简单的文本处理。
麻雀虽小,但五脏俱全,这个计算器包含编译技术中最必要的部分。
虽然这次我们只是实现了一个计算器,但所使用的技术足以实现一个简单的脚本语言的解释器了。
这个计算器分为如下几个部分:词法分析:把表达式的文本,解析成词法元素列表(tokenList)。
语法分析:把tokenList解析成语法树(syntaxTree)。
语义分析:把语法树转成汇编语言的代码(asm)汇编器:把汇编代码翻译为机器码(字节码)。
虚拟机:执行字节码。
一般的编译步聚中不包含“汇编器”和“虚拟机”,而这里之所以包含这两个部分是因为:通常编译器会直接由中间代码生成机器码,而不是生成汇编代码,而这里我之所以要生成汇编代码的原因是“调试的时候汇编的可读性很好”,如果直接生成目标代码,则会非常难用肉眼来阅读。
自己实现虚拟机的原因是:现有的机器(包括物理机和虚拟机以及模拟器)的指令虽然也很丰富,但似乎都没有直接计算“乘方”或“开方”的指令,自已实现虚拟机可以任意设计计算指令,这样可以降低整个程序的复杂度。
因汇编器与虚拟机并不是编译原理的部分,所以下文中并不会描述其实现细节,但因为计算器代码编译后的目标代码就是汇编代码,所以需要把汇编指令做一下说明(以下把这个汇编语言简称为ASM)。
这个虚拟机是基于栈来设计的,所有的计算指令的操作数都从栈中取,store命令向栈顶添加数据。
print指令用于打印当前栈顶的数据,在我们编译的汇编代码要做到:正确计算出结果,且计算完成之后的结果要刚好在栈顶,这样最后调用一个print指令即可以控制台看到计算结果。
ASM举例:例1,如果我们要计算1-2*3,则我们写出的汇编代码如下(行号是为下文解释代码方便而放上去的,不是代码的一部分):点击(此处)折叠或打开store 3store 2mulstore 1subprint对这段代码的说明如下:前两行向栈顶添加两个数字,先压入3再压入2,这样栈顶的数字是2,第二个数字是3。
第三行mul会从栈顶弹出两个数字(2和3)计算乘法,并把结果(6)再压入栈中,此时栈中只有一个数字6。
第四行向栈顶压入一个数字1,此时栈顶为1,第二个数字是6。
第五行sub指令从栈顶取出两个数字,第一个数字1做为被减数,第二个数字6做为减数,即计算1-6,并把结果压入栈中,此时栈中只有一个数字-5。
最后一行print指令不对栈做写操作,只读取栈顶的数字,并打印出来。
在这里,我们用到两个运算,mul和sub,这两个运算都是二元运算,因我在设计指令的时候,先取出来的数字是第一个操作数,所以先压入的应该是第二个操作数,这也是为什么代码中先压入的是3,之后是2,最后才是1。
例2,如果我们要计算(10 + pow(2, 3)) * sqrt(4) - 1,则我们写出的汇编代码如下(行号是为下文解释代码方便而放上去的,不是代码的一部分):点击(此处)折叠或打开store 1store 4sqrtstore 3store 2powstore 10addmulsubprint对这段代码的说明如下:这段代码稍有点复杂,但有前一段代码的经验,我们可以看到,所有的操作数的先后顺序是从右向左store的,所以store指令的顺序是固定下来的,剩下的关键是操作指令应该放在哪里。
操作指令也是有一个规律的,即:当前栈顶的数据刚刚好满足某运算时,则操作指令就放在哪里,如:store 1的时候没有任何操作的操作数都在栈中。
store 4的时候,刚刚好sqrt的操作数都在栈中,则此时加入sqrt指令。
store 3 store 2时,刚刚好可以计算pow。
store 10之后,就可以计算加法了,所以此时加入add指令。
add计算完成之后,再加上之前已计算完的sqrt指令,则此时乘法的所有操作数都在栈中了,则此时加入mul指令。
最后减操作也可以计算了,则加上sub指令。
所有计算完成之后打印出结果。
在这个例子中,我所说的“规律”其实就是“后缀表达式”。
我们平常写的算术表达式是“中缀”的,即符号在操作数中间,如1 + 2,的+ 在1和2中间,转为后缀形式即为1 2 +这里因为我对于参数顺序的设计是与“正常”顺序相反的,所以1 + 2对于这个汇编器来说,其后缀形式就应该为2 1 +大家是可以按照这个规律,相对简单的实现这个计算器——只要做好词法分析就可以按照后缀表达式的规律直接由tokenList生成汇编代码了——但我们的目的是用这个计算器的例子来讲编译,所以还是按步就班来讲。
词法分析词法分析的目的是把一段文本分解成词法元素列表,例如(10 + pow(2, 3)) * sqrt(4) - 1,做词法分析之后会分解成如下几个词法元素:这里只是做了一次文本处理——在处理之前,我们手里有的东西就是一串字符组成的字符串,在处理之后,我们按照一定的“规则”分解为多个单词。
算法是多种多样的,有创造力的程序员会想出各种办法来处理这个单词分解的问题。
在编译原理中,普遍的方式是用如下一个状态转换图来实现的在图中,“椭圆形”的是状态,状态与状态之间有一条有方向的线,这个线代表从一个状态到另一个状态的路径,在这条线上面有一个花括号代表从前一个状态到达后一个状态的输入(为方便表示,0-9表示从0到9十个数字,a-z表示从a到z二十六个字母等),如从START状态开始,输入一个数字1,就会到达INT状态。
图中蓝色的状态是终结状态,如果从START状态经过若干输入后到达终结状态,则这些输入的字符可合并为词法的合法单词——这里需要额外说明一点:在对输入进行匹配状态时采用贪婪方式,即:尽量输入更多的字符。
在识别到一个合法的词法单元之后,状态回到START继续识别下一个元素,直到没有新的元素为止。
这个状态转换图在编译原理中有一个专有名词称呼它“确定有限状态自动机”,英文简称DFA。
这里“确定”的意思是每一个状态经过一个输入字符可以确定只有一条路径到达另一个状态,“有限”的意思是,状态的个数是有限的。
对于一个复杂语言的状态数量是这个状态机的几个数量级的大小。
但我们现在的计算器只需要这几个状态就够了。
通常的DFA会由工具读取正则方法描述而生成的,而不是直接手工构造,但对我们现在设计的计算器来说,其DFA非常小,手工构造是很方便的,所以就不用工具了。
另外,如果使用工具的话,我这篇文章也不会使用现有的工具,而是自己实现一个工具。
下面举个例子:我们有一个表达式12.3 + abc,下面我来描述一下DFA的运行过程:定义一个变量s,来表示当前状态机所在的状态(初始时s = START)。
输入第一个字符1,此时START状态可接受这个输入1,到达INT状态,则变量s赋值为INT状态,此时可看到INT状态的颜色是蓝色表示当前可识别为一个合法的词法元素,但因为我们的规则是贪婪匹配,所以我们还要看看是否还能够匹配更多的字符。
输入第二个字符2,此时INT状态也可以接受这人输入,并到达INT状态(转了一个圈又回到原来的状态),此时变量s赋值为INT状态。
再输入第三个字符. ,此时INT状态可接受. 到达NUMBER状态,此时变量s赋值为NUMBER状态。
此时我们再向前看一个字符+ ,此时的状态NUMBER无法接受这个字符了,同时我们可在看到NUMBER状态的颜色是蓝色的,表示当前状态可识别一个合法的词法元素,即:从START开始到当前我们一共经历的输入为12.3,则这个单词做为第一个合法的词法元素。
第一个词法元素识别成功之后,变量s要回到START状态,并继续输入+ ,此时从START 状态可到达ADD状态,且ADD状态并不允许接受任何输入,同时ADD状态的颜色也是蓝色的,则我们又识别出第二个词法元素+ 。
在识别到第二个词法元素之后,变更s要回到START状态,并继续输入a,此时START 状态可由a指向的路径到达ID状态,此时s赋值为新的状态ID。
现在的情况与识别NUMBER的情况类似,当前的状态也是终结状态,但按贪婪匹配的原则还要继续看看是否可以匹配到新的输入。
后面的b和c都在ID一个状态里转圈,我就不在赘述了,这样我们就识别到了最后一个词法元素abc了。
用如上过程的方法可以识别任何正确的算术表达式,但还有几点需要特别说明:如何识别错误:目前我见过的语言规范都在描述如何正确的编译一个语言,但没有一个规范有描述如何报错的,所以我们目前能做的是只要按正常的走法走不通了,那就是错了,就要报错,并尽可能提供详细的错误信息。
对空白的识别:我在DFA中并没有画识别空白的部分,原因是对于计算器程序来说,空白完全没有用处,所以我只是在代码中直接忽略这个输入,以免状态机无法识别空白,同时在识别到词法元素之后,去掉单词前后的空白。
对于某些语言来说,空白是有意义的,需要做为词法元素识别出来,不能忽略掉。
对于词法元素的表示:通常我们会用一个类型Token来表示一个词法元素,Token中有两个属性,一个用于表示这个Token的类型,另一个用于表示内容,只有数字与标识符才需要使用Token类型的内容属性,其它的类型因为同一类型只有一种表示的可能,所以就不需要再把内容保存下来了(如ADD的内容一定是+)。
关于标识符:DFA中的ID状态用于识别标识符,这里的标识符包括自定义的变量,也包括函数名。
在DFA的设计过程中,我们可以选择把普通标识符与保留字做为不同的状态,也可以用使用同一个状态。
我们现在的设计就使用了一个ID状态表示所有的标识符,而在识别到一个ID之后,我们在看是否是一个保留字,这样在返回Token对象时设置不同的类型。
对于INT和NUMBER:这个计算器的所有计算都使用的是double类型的数字,所在虽然我们的词法可以识别到INT,但我们定义Token的类型时,就只定义一个NUMBER类型,INT或NUMBER状态确定的单词都返回NUMBER这个类型的Token对象。