基于编译原理的计算器设计与实现

合集下载

汇编语言课程设计四则运算计算器..【范本模板】

汇编语言课程设计四则运算计算器..【范本模板】

微机原理实验报告汇编语言课程设计报告( 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编译原理实现计算器(测试驱动讲解)

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 计算器编译原理下面是一个简单的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文档良心出品)

(完整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 压栈。

基于编译原理的计算器设计与实现

基于编译原理的计算器设计与实现

基于编译原理的计算器设计与实现首先看一下这个计算器的功能: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)汇编器:把汇编代码翻译为机器码(字节码)。

虚拟机:执行字节码。

一般的编译步聚中不包含“汇编器”和“虚拟机”,而这里之所以包含这两个部分是因为:通常编译器会直接由中间代码生成机器码,而不是生成汇编代码,而这里我之所以要生成汇编代码的原因是“调试的时候汇编的可读性很好”,如果直接生成目标代码,则会非常难用肉眼来阅读。

自己实现虚拟机的原因是:现有的机器(包括物理机和虚拟机以及模拟器)的指令虽然也很丰富,但似乎都没有直接计算“乘方”或“开方”的指令,自已实现虚拟机可以任意设计计算指令,这样可以降低整个程序的复杂度。

基于编译原理的简单计算器的设计与实现

基于编译原理的简单计算器的设计与实现

基于编译原理的简单计算器的设计与实现
设计计算器的主要任务是定义运算符和相应的优先级,并为它
们编写按优先级计算表达式的算法。

以下是基于编译原理的计算器
的设计和实现步骤:
1. 词法分析:将用户输入的算术表达式分解成一个个词法单元(token),比如加号、数字、括号、减号等。

2. 语法分析:通过使用递归下降分析法,将词法单元按照特定
的规则进行组合,形成一个抽象语法树(AST),表示表达式的结构
和含义。

3. 语义分析:在AST的基础上进行语义分析,检查表达式中是
否存在语义错误,比如除数为零、变量未定义等。

4. 优化处理:对表达式进行优化处理,比如常量折叠、变量合并、代数简化等,以提高计算效率。

5. 生成中间代码:将AST转换成一种中间表示形式,比如三地
址码(three-address code),这种形式可以方便地生成计算机底
层代码。

6. 代码生成:根据中间代码生成目标机器的汇编代码或机器码,执行计算操作。

7. 输出结果:将计算结果显示给用户。

以上是基于编译原理的计算器的设计和实现步骤,其中重点是
语法分析和代码生成,这些步骤需要仔细考虑各种运算符的优先级
和结合性,以保证表达式的计算结果正确无误。

汇编语言课程设计报告 实现加减乘除四则运算的计算器

汇编语言课程设计报告   实现加减乘除四则运算的计算器

汇编语言课程设计报告实现加减乘除四则运算的计算器汇编语言课程设计报告-实现加减乘除四则运算的计算器.(2021--2021年度第2学期)汇编语言课程设计报告实现加减乘除四则运算的计算器专业计算机科学与技术学生姓名班学班号指导教师完成日期..目录目录............................................................................ ..........................................21概述............................................................................ .......................................11.1设计目的............................................................................ ................................11.2设计内容............................................................................ ................................12系统需求分析............................................................................ ...............................12.1系统目标............................................................................ ................................12.2主体功能............................................................................ ................................12.3开发环境............................................................................ ................................13系统概要设计...........................................................................................................23.1系统的功能模块划分............................................................................ ............23.2系统流程图............................................................................ ............................34系统详细设计............................................................................ .............................35测试............................................................................ .............................................45.1测试方案............................................................................ ................................45.2测试结果............................................................................ ................................46小结............................................................................ .............................................5参考文献............................................................................ ........................................6附录............................................................................ ..........................................7附录源程序清单............................................................................ (7)..计算器1概述1.1设计目的实现加法、减法、乘法和除法四种运算本课程设计是在学完教学大纲规定的全部内容、完成所有实践环节的基础上,旨在深化学生学习的汇编语言课程基本知识,进一步掌握汇编语言程序设计方法,提高分析问题、解决问题的综合应用能力。

编译原理实现一个简单的计算器程序

编译原理实现一个简单的计算器程序

《编译原理》实验报告专业:学号:班级:姓名:实验题目:设计,实现一个简单的计算器程序实验时间:指导教师:实验成绩:1实验目的1.1实现一个简单计算器2实验要求2.1单词的构词规则有明确的定义;2.2编写的分析程序能够正确识别源程序中的语法符号;2.3计算器源程序的以.c格式输出2.4对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成整个源程序的词法分析,语法分析;2.5计算器能够实现加,减,乘,除,混合运算,多项式运算。

3实验环境3.1Windows XP3.2Flex词法分析工具3.3Visual Studio C++ 6.04实验原理4.1多项式计算器的实现,采用后缀表达式来对输入的计算表达式进行计算4.2对后缀表达式进行符号识别,词法分析,语法分析4.3编写计算器的源程序,使用Flex工具生成计算器的C语言程序4.4对生成的程序进行相应的修改,再进行编译,连接,运行,测试得到可以用于进行多项式运算的源程序。

5软件设计与编程5.1程序源代码:5.2新建文件夹5.3将Flex工具复制到该文件夹下5.4在DOS环境学生成目标源程序5.5在Visual Studio C++6.0环境下进行相应的修改,添加main方法和打开文件的方法6程序测试结果6.1编写源代码6.2使用Flex生成C代码:6.3 在V isual Studio C++6.0上运行生成的”.c”文件文件:y.ta.h#ifndef YYTOKENT YPE# define YYT OKENT YPEenum yytokentype {CLEAR = 258,EXIT = 259,LIST = 260,ERASE = 261,DEC = 262,HEX = 263,OCT = 264,HELP = 265,NUM = 266,REG = 267,ADD = 268,SUB = 269,MUL = 270,DIV = 271,MOD = 272,LSHIFT = 273,RSHIFT = 274,AND = 275,OR = 276,NOT = 277,LESS = 278,MORE = 279,BIT AND = 280,BITOR = 281,BITXOR = 282,BITREV = 283,SIN = 284,COS = 285,T AN = 286,ABS = 287,SQRT = 288,LOG = 289,RMINUS = 290};//前面定义过,此处省略宏定义#if ! defined (YYST YPE) && ! defined(YYSTYPE_IS_DECLARED) typedef int YYST YPE;# define yystype YYSTYPE /* obsolescent; will be withdrawn */# define YYSTYPE_IS_DECLARED 1# define YYSTYPE_IS_TRIVIAL 1 #endifextern YYST YPE yylval;文件:calc.l 核心程序%{#define YYSTYPE double#define BIGINT long#include <ctype.h>#include "y.tab.h"%}digit [0-9]xdigit [0-9a-fA-F]odigit [0-7]decnum(0(\.{digit}+)?)|([1-9]{digit} *(\.{digit}+)?)octnum0{odigit}+hexnum 0(x|X){xdigit}+ reg [a-zA-Z]opt1"+"|"-"|"*"|"/"|"&"|"|"|" %"|"^"|"~"|"!"|"<"|">"opt2(&&)|(\|\|)|(\<\<)|(\>\>)exit((E|e)(X|x)(I|i)(T|t))|((Q|q)( U|u)(I|i)(T|t))clear(C|c)(L|l)(E|e)(A|a)(R|r) list (L|l)(I|i)(S|s)(T|t) erase(E|e)(R|r)(A|a)(S|s)(E|e)hex (H|h)(E|e)(X|x)oct (O|o)(C|c)(T|t)dec (D|d)(E|e)(C|c) help (H|h)(E|e)(L|l)(P|p) sin(S|s)(I|i)(N|n) cos(C|c)(O|o)(S|s)log(L|l)(O|o)(G|g)tan(T|t)(A|a)(N|n)abs(A|a)(B|b)(S|s)sqrt(S|s)(Q|q)(R|r)(T|t)%%int i ;BIGINT val;[" "; \t]{ }{decnum}{sscanf(yytext,"%lf",&yylval);return(NUM); }{octnum} {i=1;v al=0;while(i<yyleng){val=(val<<3)+yytext[i]-'0';i++;}yylval=val;return(NUM);}{hexnum} {i=2;v al=0;while(i<yyleng){if(islower(yytext[i]))val=(val<<4)+yytext[i]-'a'+10;elseif(isupper(yytext[i]))val=(val<<4)+yytext[i]-'A'+10;elseval=(val<<4)+yytext[i]-'0';i++;}yylval=val;return(NUM);}{reg} {if(islower(yytext[0]))yylval=yytext[0]-'a';elseyylval=yytext[0]-'A';return(REG);}{opt1} {switch(yytext[0]){case'+':return ADD;break;case'-':return SUB;break;case'*':return MUL;break;case'/':return DIV;break;case'%':return MOD;break;case'^':return BITXOR;break;case'&':return BITAND;break;case'|':return BITOR;break;case'<':return LESS;break;case'>':return MORE;break;case'!':return NOT;break;case'~':return BITREV;break;}}{opt2} {switch(yytext[0]){case'&':return AND;break;case'|':return OR;break;case'<':return LSHIFT;break;case'>':return RSHIFT;break;}}{sin} {return (SIN);}{cos} {return (COS);}{tan} {return (TAN);}{log} {return (LOG);}{abs} {return (ABS);}{sqrt} {return (SQRT);}{clear} {return(CLEAR);}{exit} {return(EXIT);}{list} {return(LIST);}{erase} {return(ERASE);}{hex} {return(HEX);}{oct} {return(OCT);}{dec} {return(DEC);}{help} {return(HELP);}.|\n {return(yytex t[0]);}文件:y.tab.c部分代码:#define YYBISON 1/* Skeleton name. */#define YYSKELETON_NAME"yacc.c"/* Pure parsers. */#define YYPURE 0/* Using locations. */#define YYLSP_NEEDED 0/* T okens. */#ifndef YYTOKENT YPE# define YYT OKENT YPE/* Put the tokens into the symboltable, so that GDB and otherdebuggersknow about them. */enum yytokentype {前面定义过,此处省略};/* Copy the first part of userdeclarations. */#line 1 "calc.y"//前面定义过,此处省略宏定义#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <math.h>#include "lex.yy.c" //这是词法分析器生成的文件,必须包含!YYSTYPE reg[26]={0};BIGINT ival;enum Display{DEC_ON, HEX_ON,OCT_ON};enum Display dflag=DEC_ON;int i;/* Enabling traces. */#ifndef YYDEBUG# define YYDEBUG 0#endif/* Enabling verbose error messages.*/#ifdef YYERROR_VERBOSE# undef YYERROR_V ERBOSE# define YYERROR_V ERBOSE 1#else# define YYERROR_V ERBOSE 0#endif#if ! defined (YYST YPE) && !defined(YYSTYPE_IS_DECLARED)typedef int YYST YPE;# define yystype YYSTYPE /*obsolescent; will be withdrawn */# defineYYSTYPE_IS_DECLARED 1# define YYSTYPE_IS_TRIVIAL 1#endif/* Copy the second part of userdeclarations. *//* Line 214 of yacc.c. */#line 173 "y.tab.c"#if ! defined (yyoverflow) ||YYERROR_V ERBOSE/* The parser invokes alloca ormalloc; define the necessarysymbols. */# if YYST ACK_USE_ALLOCA# define YYST ACK_ALLOCalloca# else# ifndefYYST ACK_USE_ALLOCA# if defined (alloca) || defined (_ALLOCA_H)# define YYST ACK_ALLOC alloca# else# ifdef __GNUC__# define YYST ACK_ALLOC __builtin_alloca# endif# endif# endif# endif# ifdef YYST ACK_ALLOC/* Pacify GCC's `empty if-body' warning. */# define YYST ACK_FREE(Ptr) do { /* empty */; } while (0)# else# if defined (__STDC__) || defined (__cplusplus)# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */# define YYSIZE_T size_t# endif# define YYST ACK_ALLOC malloc# define YYST ACK_FREE free # endif#endif /* ! defined (yyoverflow) || YYERROR_V ERBOSE */#if (! defined (yyoverflow) \&& (! defined (__cplusplus) \||(YYSTYPE_IS_TRIVIAL)))/* A type that is properly aligned for any stack member. */union yyalloc{short yyss;YYSTYPE yyvs;};/* T he size of the maximum gap between one aligned stack and the next. */# define YYST ACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)/* The size of an array large to enough to hold all stacks, each with N elements. */# define YYST ACK_BYT ES(N) \ ((N) * (sizeof (short) + sizeof (YYSTYPE))\+YYST ACK_GAP_MAXIMUM)/* Copy COUNT objects from FROM to T O. T he source and destination donot overlap. */# ifndef YYCOPY# if 1 < __GNUC__# define YYCOPY(T o, From, Count) \__builtin_memcpy (T o, From, (Count) * sizeof (*(From))) # else# define YYCOPY(T o, From, Count) \do\{\register YYSIZ E_T yyi;\for (yyi = 0; yyi < (Count); yyi++) \(T o)[yyi] = (From)[yyi];\}\while (0)# endif# endif /* Relocate ST ACK from its oldlocation to the new one. Thelocal variables YYSIZE andYYST ACKSIZE give the old andnew number ofelements in the stack, andYYPT R gives the new location ofthestack. Advance YYPTR to aproperly aligned location for thenextstack. */# defineYYST ACK_RELOCATE(Stack)\do{\YYSIZE_T yynewbytes;YYCOPY (&yyptr->Stack,Stack, yysize);Stack = &yyptr->Stack;\yynewbytes = yystacksize *sizeof (*Stack) +YYST ACK_GAP_MAXIMUM; \yyptr += yynewbytes /sizeof (*yyptr);\}\while (0)#endif#if defined (__ST DC__) || defined(__cplusplus)typedef signed charyysigned_char;#elsetypedef short yysigned_char;#endif/* YYFINAL -- State number of thetermination state. */#define YYFINAL 2/* YYLAST -- Last index inYYT ABLE. */#define YYLAST 188/* YYNTOKENS -- Number ofterminals. */#define YYNT OKENS 40/* YYNNTS -- Number ofnonterminals. */#define YYNNTS 5/* YYNRULES -- Number of rules.*/#define YYNRULES 42/* YYNRULES -- Number of states.*/#define YYNST ATES 73/* YYTRANSLATE(YYLEX) --Bison symbol numbercorresponding to YYLEX. */#define YYUNDEFTOK 2#define YYMAXUT OK 290#define YYTRANSLAT E(YYX)\((unsigned int) (YYX) <=YYMAXUT OK ?yytranslate[YYX] :YYUNDEFTOK)/* YYTRANSLATE[YYLEX] --Bison symbol numbercorresponding to YYLEX. */static const unsigned charyytranslate[] ={省略数据信息};/* YYRHS -- A `-1'-separated list ofthe rules' RHS. */static const yysigned_char yyrhs[] ={省略数据信息};/* YYRLINE[YYN] -- source linewhere rule number YYN wasdefined. */static const unsigned char yyrline[]={省略数据信息};#endif#if YYDEBUG ||YYERROR_V ERBOSE/* YYT NME[SYMBOL-NUM] --String name of the symbolSYMBOL-NUM.First, the terminals, then,starting at YYNT OKENS,nonterminals. */static const char *const yytname[] ={"$end", "error", "$undefined","CLEAR", "EXIT", "LIST","ERASE", "DEC","HEX", "OCT", "HELP", "NUM","REG", "ADD", "SUB", "MUL","DIV", "MOD","LSHIFT", "RSHIFT", "AND","OR", "NOT", "LESS", "MORE","BIT AND","BITOR", "BITXOR","BITREV", "SIN", "COS", "T AN","ABS", "SQRT", "LOG","RMINUS", "'\\n'", "'='", "'('", "')'","$accept", "lines", "statement","expr", "cmdline", 0};#endif# ifdef YYPRINT/* YYT OKNUM[YYLEX-NUM] --Internal token numbercorresponding totoken YYLEX-NUM. */static const unsigned shortyytoknum[] ={省略数据信息};# endif/* YYR1[YYN] -- Symbol numberof symbol that rule YYN derives.*/static const unsigned char yyr1[] ={省略数据信息};/* YYDEF ACT[ST ATE-NAME] --Default rule to reduce with in stateST ATE-NUM when YYT ABLEdoesn't specify something else to do.Zeromeans the default is an error.*/static const unsigned char yydefact[]={ 省略数据信息};/* YYDEFGOT O[NT ERM-NUM].*/static const yysigned_charyydefgoto[] ={省略数据};/* YYPACT[ST AT E-NUM] -- Indexin YYT ABLE of the portiondescribingST ATE-NUM. */#define YYPACT_NINF -28static const short yypact[] ={省略数据信息};/* YYPGOTO[NTERM-NUM]. */static const yysigned_char yypgoto[]={省略数据信息};/*YYT ABLE[YYPACT[ST ATE-NUM]]. What to do in stateST ATE-NUM. Ifpositive, shift that token. Ifnegative, reduce the rule whichnumber is the opposite. If zero,do what YYDEF ACT says.If YYT ABLE_NINF, syntaxerror. */#define YYT ABLE_NINF -1static const unsigned char yytable[]={省略数据信息};#if ! defined (YYSIZ E_T) &&defined (__SIZE_TYPE__)# define YYSIZ E_T__SIZE_TYPE__#endif#if ! defined (YYSIZ E_T) &&defined (size_t)# define YYSIZE_T size_t#endif#if ! defined (YYSIZE_T)# if defined (__STDC__) || defined(__cplusplus)# include <stddef.h> /*INFRINGES ON USER NAMESPACE */# define YYSIZ E_T size_t# endif#endif#if ! defined (YYSIZE_T)# define YYSIZE_T unsigned int#endif#define yyerrok (yyerrstatus= 0)#define yyclearin (yychar =YYEMPT Y)#define YYEMPTY (-2)#define YYEOF 0#define YYACCEPT gotoyyacceptlab#define YYABORT gotoyyabortlab#define YYERROR gotoyyerrlab1/* Like YYERROR except do callyyerror. T his remains heretemporarilyto ease the transition to the newmeaning of YYERROR, for GCC.Once GCC version 2 hassupplanted version 1, this can go.*/#define YYFAIL gotoyyerrlab#define YYRECOVERING()(!!yyerrstatus)#define YYBACKUP(T oken, V alue)\do\if (yychar == YYEMPT Y &&yylen == 1)\{\yychar = (T oken);\yylval = (V alue);\yytoken = YYTRANSLATE(yychar);\YYPOPST ACK;\goto yybackup;\ }\ else \{ \yyerror ("syntax error: cannot back up");\YYERROR;}\ while (0)#define YYTERROR 1#define YYERRCODE 256/* YYLLOC_DEF AULT -- Compute the default location (before the actionsare run). */#ifndef YYLLOC_DEF AULT# define YYLLOC_DEF AULT(Current, Rhs, N) \Current.first_line = Rhs[1].first_line; \ Current.first_column = Rhs[1].first_column; \ st_line = Rhs[N].last_line; \ st_column = Rhs[N].last_column;#endif/* YYLEX -- calling `yylex' with the right arguments. */#ifdef YYLEX_PARAM# define YYLEX yylex (YYLEX_PARAM)#else# define YYLEX yylex ()#endif/* Enable debugging if requested. */#if YYDEBUG# ifndef YYFPRINTF# include <stdio.h> /* INFRINGES ON USER NAME SPACE */# define YYFPRINTF fprintf# endif# define YYDPRINTF(Args)\do {\if (yydebug)\YYFPRINTF Args;\} while (0)# define YYDSYMPRINT(Args)\do {\if (yydebug)\yysymprint Args;\} while (0)# define YYDSYMPRINTF(T itle, T oken, V alue, Location) \do {\if (yydebug)\ {\YYFPRINTF (stderr, "%s ", Title); \yysymprint (stderr,\T oken, V alue);\YYFPRINTF (stderr, "\n");\}\} while (0)/*------------------------------------------------------------------.| yy_stack_print -- Print the statestack from its BOTTOM up to its || TOP (cinluded).|`------------------------------------------------------------------*/#if defined (__ST DC__) || defined(__cplusplus)static voidyy_stack_print (short *bottom, short*top)#elsestatic voidyy_stack_print (bottom, top)short *bottom;short *top;#endif{YYFPRINTF (stderr, "Stacknow");for (/* Nothing. */; bottom <= top;++bottom)YYFPRINTF (stderr, " %d",*bottom);YYFPRINTF (stderr, "\n");}# defineYY_ST ACK_PRINT(Bottom, T op)\do {\if (yydebug)\yy_stack_print ((Bottom),(T op)); \} while (0)#if defined (__ST DC__) || defined(__cplusplus)static voidyy_reduce_print (int yyrule)#elsestatic voidyy_reduce_print (yyrule)int yyrule;#endif{int yyi;unsigned int yylno =yyrline[yyrule];YYFPRINTF (stderr, "Reducingstack by rule %d (line %u), ",yyrule - 1, yylno);/* Print the symbols beingreduced, and their result. */for (yyi = yyprhs[yyrule]; 0 <=yyrhs[yyi]; yyi++)YYFPRINTF (stderr, "%s ",yytname [yyrhs[yyi]]);YYFPRINTF (stderr, "-> %s\n",yytname [yyr1[yyrule]]);}# defineYY_REDUCE_PRINT(Rule)\do {\if (yydebug)\yy_reduce_print (Rule);\} while (0)/* Nonzero means print parse trace.It is left uninitialized so thatmultiple parsers can coexist. */int yydebug;#else /* !YYDEBUG */# define YYDPRINTF(Args)# define YYDSYMPRINT(Args)# define YYDSYMPRINTF(T itle,T oken, V alue, Location)# defineYY_ST ACK_PRINT(Bottom, T op)# defineYY_REDUCE_PRINT(Rule)#endif /* !YYDEBUG *//* YYINIT DEPTH -- initial size ofthe parser's stacks. */#ifndef YYINIT DEPTH# define YYINIT DEPTH 200#endif/* YYMAX DEPT H -- maximumsize the stacks can grow to(effective onlyif the built-in stack extensionmethod is used).Do not make this value too large;the results are undefined ifSIZE_MAX <YYST ACK_BYT ES(YYMAXDEPTH)evaluated with infinite-precisioninteger arithmetic. */#if YYMAX DEPT H == 0# undef YYMAX DEPTH#endif#ifndef YYMAXDEPTH# define YYMAX DEPTH 10000#endif#if YYERROR_VERBOSE# ifndef yystrlen# if defined (__GLIBC__) &&defined (_STRING_H)# define yystrlen strlen# else/* Return the length of YYSTR. */static YYSIZE_T# if defined (__STDC__) ||defined (__cplusplus)yystrlen (const char *yystr)# elseyystrlen (yystr)const char *yystr;# endif{register const char *yys = yystr;while (*yys++ != '\0')continue;return yys - yystr - 1;}# endif# endif# ifndef yystpcpy# if defined (__GLIBC__) &&defined (_STRING_H) && defined(_GNU_SOURCE)# define yystpcpy stpcpy# elsestatic char *# if defined (__STDC__) ||defined (__cplusplus)yystpcpy (char *yydest, const char*yysrc)# elseyystpcpy (yydest, yysrc)char *yydest;const char *yysrc;# endif{register char *yyd = yydest;register const char *yys = yysrc;while ((*yyd++ = *yys++) != '\0')continue;return yyd - 1;}# endif# endif#endif /* !YYERROR_VERBOSE*/#if YYDEBUG#if defined (__ST DC__) || defined(__cplusplus)static voidyysymprint (FILE *yyoutput, intyytype, YYSTYPE *yyvaluep)#elsestatic voidyysymprint (yyoutput, yytype,yyvaluep)FILE *yyoutput;int yytype;YYSTYPE *yyvaluep;#endif{/* Pacify ``unused variable''warnings. */(void) yyvaluep;if (yytype < YYNTOKENS){YYFPRINTF (yyoutput,"token %s (", yytname[yytype]);# ifdef YYPRINTYYPRINT (yyoutput,yytoknum[yytype], *yyvaluep);# endif}elseYYFPRINTF (yyoutput,"nterm %s (", yytname[yytype]);switch (yytype){default:break;}YYFPRINTF (yyoutput, ")");}#endif /* ! YYDEBUG *//*-----------------------------------------------.| Release the memory associated tothis symbol. |`-----------------------------------------------*/#if defined (__ST DC__) || defined(__cplusplus)static voidyydestruct (int yytype, YYSTYPE*yyvaluep)#elsestatic voidyydestruct (yytype, yyvaluep)int yytype;YYSTYPE *yyvaluep;#endif{(void) yyvaluep;switch (yytype){default:break;}}#ifdef YYPARSE_PARAM# if defined (__STDC__) || defined(__cplusplus)int yyparse (void*YYPARSE_PARAM);# elseint yyparse ();# endif#else /* ! YYPARSE_PARAM */#if defined (__ST DC__) || defined(__cplusplus)int yyparse (void);#elseint yyparse ();#endif#endif /* ! YYPARSE_PARAM *//* T he lookahead symbol. */int yychar;/* T he semantic value of thelookahead symbol. */YYSTYPE yylval;/* Number of syntax errors so far.*/int yynerrs;/*----------.| yyparse. |`----------*/#ifdef YYPARSE_PARAM# if defined (__STDC__) || defined (__cplusplus)int yyparse (void *YYPARSE_PARAM)# elseint yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM;# endif#else /* ! YYPARSE_PARAM */#if defined (__ST DC__) || defined (__cplusplus)intyyparse (void)#elseintyyparse ()#endif#endif{register int yystate;register int yyn;int yyresult;/* Number of tokens to shift before error messages enabled. */ int yyerrstatus;/* Lookahead token as an internal (translated) token number. */int yytoken = 0;/* Three stacks and their tools:`yyss': related to states,`yyvs': related to semantic values,`yyls': related to locations.Refer to the stacks thru separate pointers, to allow yyoverflowto reallocate them elsewhere. *//* The state stack. */short yyssa[YYINIT DEPT H]; short *yyss = yyssa;register short *yyssp;/* The semantic value stack. */ YYSTYPEyyvsa[YYINIT DEPT H]; YYSTYPE *yyvs = yyvsa; register YYST YPE *yyvsp;#define YYPOPST ACK (yyvsp--, yyssp--)YYSIZ E_T yystacksize = YYINIT DEPTH;/* The variables used to return semantic value and location from theaction routines. */ YYSTYPE yyval;/* When reducing, the number of symbols on the RHS of the reduced rule. */int yylen;YYDPRINTF ((stderr, "Starting parse\n"));yystate = 0;yyerrstatus = 0;yynerrs = 0;yychar = YYEMPT Y;yyssp = yyss;yyvsp = yyvs;goto yysetstate; yynewstate:/* In all cases, when you get here,the value and location stackshave just been pushed. sopushing a state here evens thestacks.*/yyssp++;yysetstate:*yyssp = yystate;if (yyss + yystacksize - 1 <=yyssp){/* Get the current used sizeof the three stacks, in elements. */YYSIZE_T yysize = yyssp -yyss + 1;#ifdef yyoverflow{/* Give user a chance toreallocate the stack. Use copies ofthese so that the &'sdon't force the real ones intomemory. */YYSTYPE *yyvs1 = yyvs;short *yyss1 = yyss;/* Each stack pointeraddress is followed by the size ofthedata in use in that stack,in bytes. This used to be aconditional around justthe two extra args, but that mightbe undefined ifyyoverflow is a macro. */yyoverflow ("parser stackoverflow",&yyss1, yysize* sizeof (*yyssp),&yyvs1, yysize* sizeof (*yyvsp),&yystacksize);yyss = yyss1;yyvs = yyvs1;}#else /* no yyoverflow */# ifndef YYST ACK_RELOCATEgoto yyoverflowlab;# else/* Extend the stack our ownway. */if (YYMAXDEPT H <=yystacksize)goto yyoverflowlab;yystacksize *= 2;if (YYMAX DEPT H <yystacksize)yystacksize =YYMAXDEPTH;{short *yyss1 = yyss;union yyalloc *yyptr =(union yyalloc *)YYST ACK_ALLOC(YYST ACK_BYT ES(yystacksize));if (! yyptr)goto yyoverflowlab;YYST ACK_RELOCATE(yyss);YYST ACK_RELOCATE(yyvs);# undef YYST ACK_RELOCATEif (yyss1 != yyssa)YYST ACK_FREE(yyss1);}# endif#endif /* no yyoverflow */yyssp = yyss + yysize - 1;yyvsp = yyvs + yysize - 1;YYDPRINTF ((stderr,"Stack size increased to %lu\n",(unsigned longint) yystacksize));if (yyss + yystacksize - 1 <=yyssp)YY ABORT;}YYDPRINTF ((stderr, "Enteringstate %d\n", yystate));goto yybackup;yybackup:/* Do appropriate processing giventhe current state. *//* Read a lookahead token if weneed one and don't already have one.*//* yyresume: *//* First try to decide what to dowithout reference to lookaheadtoken. */yyn = yypact[yystate];if (yyn == YYPACT_NINF)goto yydefault;/* Not known => get a lookaheadtoken if don't already have one. *//* YYCHAR is either YYEMPT Yor YYEOF or a valid lookaheadsymbol. */if (yychar == YYEMPT Y){YYDPRINTF ((stderr,"Reading a token: "));yychar = YYLEX;}if (yychar <= YYEOF){yychar = yytoken = YYEOF;YYDPRINTF ((stderr, "Nowat end of input.\n"));}else{yytoken = YYTRANSLATE(yychar);YYDSYMPRINTF ("Nexttoken is", yytoken, &yylval,&yylloc);}/* If the proper action on seeingtoken YYT OKEN is to reduce or todetect an error, take thataction. */yyn += yytoken;if (yyn < 0 || YYLAST < yyn ||yycheck[yyn] != yytoken)goto yydefault;yyn = yytable[yyn];if (yyn <= 0){if (yyn == 0 || yyn ==YYT ABLE_NINF)goto yyerrlab;yyn = -yyn;goto yyreduce;}if (yyn == YYFINAL)YYACCEPT;/* Shift the lookahead token. */YYDPRINTF ((stderr, "Shiftingtoken %s, ", yytname[yytoken]));/* Discard the token being shiftedunless it is eof. */if (yychar != YYEOF)yychar = YYEMPTY;*++yyvsp = yylval;/* Count tokens shifted sinceerror; after three, turn off errorstatus. */if (yyerrstatus)yyerrstatus--;yystate = yyn;goto yynewstate;/*-----------------------------------------------------------.| yydefault -- do the default actionfor the current state. |`-----------------------------------------------------------*/yydefault:yyn = yydefact[yystate];if (yyn == 0)goto yyerrlab;goto yyreduce;/*-----------------------------.| yyreduce -- Do a reduction. |`-----------------------------*/yyreduce:/* yyn is the number of a rule toreduce with. */yylen = yyr2[yyn];/* If YYLEN is nonzero,implement the default value of theaction:`$$ = $1'.Otherwise, the following linesets YYV AL to garbage.This behavior isundocumented and Bisonusers should not rely upon it.Assigning to YYV ALunconditionally makes theparser a bit smaller, and it avoids aGCC warning that YYV ALmay be used uninitialized. */yyval = yyvsp[1-yylen];YY_REDUCE_PRINT (yyn);switch (yyn){case 3:#line 39 "calc.y"{printf("--> ");}break;case 4:#line 40 "calc.y"{yyerrok;printf("\n--> ");}break;case 7:#line 45 "calc.y"{if(dflag==DEC_ON)printf("\t=%g\n--> " , yyvsp[0] );elseif(dflag==HEX_ON)printf( "\t=0x%08X\n--> " , (BIGINT)yyvsp[0] );elseprintf( "\t=0%o\n--> " ,(BIGINT)yyvsp[0] );}break;case 8:#line 50 "calc.y"{i=(int)yyvsp[-2]; reg[i] = yyvsp[0] ;if(dflag==DEC_ON)printf( "\t%c=%g\n--> " ,'a'+i,reg[i] );else if(dflag==HEX_ON)printf( "\t%c=0x%08X\n--> " ,'a'+i,(BIGINT)reg[i] );else printf( "\t%c=0%o\n--> " ,'a'+i,(BIGINT)reg[i] );}break;case 9:#line 58 "calc.y"{ yyval = yyvsp[-2] + yyvsp[0] ; }break;case 10:#line 59 "calc.y"{ yyval = yyvsp[-2] - yyvsp[0] ; }break;case 11:#line 60 "calc.y"{ yyval = yyvsp[-2] * yyvsp[0] ; }break;case 12:#line 61 "calc.y"{ yyval = yyvsp[-2] / yyvsp[0] ; }break;case 13:#line 62 "calc.y"{ yyval = (BIGINT)yyvsp[-2] % (BIGINT)yyvsp[0] ; }break;case 14:#line 63 "calc.y"{ yyval = (BIGINT)yyvsp[-2] & (BIGINT)yyvsp[0] ; }break;case 15:#line 64 "calc.y"{ yyval = (BIGINT)yyvsp[-2] | (BIGINT)yyvsp[0] ; }break;case 16:#line 65 "calc.y"{ yyval = (BIGINT)yyvsp[-2] ^ (BIGINT)yyvsp[0] ; }break;case 17:#line 66 "calc.y"{ yyval = (BIGINT)yyvsp[-2] << (BIGINT)yyvsp[0] ; }break;case 18:#line 67 "calc.y"{ yyval = (BIGINT)yyvsp[-2] >> (BIGINT)yyvsp[0] ; }break;case 19:#line 68 "calc.y"{ yyval = (BIGINT)yyvsp[-2] && (BIGINT)yyvsp[0] ; }break;case 20:#line 69 "calc.y"{ yyval = (BIGINT)yyvsp[-2] || (BIGINT)yyvsp[0] ; }break;case 21:#line 70 "calc.y"{ yyval = yyvsp[-2]<yyvsp[0]?1:0; }break;case 22:#line 71 "calc.y"{ yyval = yyvsp[-2]>yyvsp[0]?1:0; }break;case 23:#line 72 "calc.y"{ yyval = yyvsp[-1] ; }break;case 24: #line 73 "calc.y"{ yyval = -yyvsp[0] ; }break;case 25:#line 74 "calc.y"{ yyval =~((BIGINT)yyvsp[0]); }break;case 26:#line 75 "calc.y"{ yyval= !( (BIGINT)yyvsp[0] ) ; }break;case 27:#line 76 "calc.y"{ yyval = yyvsp[0] ; }break;case 28:#line 77 "calc.y"{ ival=(int)yyvsp[0];yyval =reg[ival] ; }break;case 29:#line 78 "calc.y"{ yyval =sin(yyvsp[0]) ; }break;case 30:#line 79 "calc.y"{ yyval =cos(yyvsp[0]) ; }break;case 31:#line 80 "calc.y"{ yyval =tan(yyvsp[0]) ; }break;case 32:#line 81 "calc.y"{ yyval =log(yyvsp[0]) ; }break;case 33:#line 82 "calc.y"{ yyval =abs(yyvsp[0]) ; }break;case 34:#line 83 "calc.y"{ yyval =sqrt(yyvsp[0]) ; }break;case 35:#line 86 "calc.y"{ exit(0); }break;case 36:#line 87 "calc.y"{ printf("\033[2J\033[1;1H\n-->"); }break;case 37:#line 88 "calc.y"{ dflag=HEX_ON; printf(">>Hex display mod on!\n--> "); }break;case 38:#line 89 "calc.y"{ dflag=DEC_ON; printf(">>Dec display mod on!\n--> "); }break;case 39:#line 90 "calc.y"{ dflag=OCT_ON; printf(">>Oct display mod on!\n--> "); }break;case 40:#line 91 "calc.y"{for(i=0;i<26;i++){if(dflag==DEC_ON)printf("\t%c=%g\n",'a'+i,reg[i]);elseif(dflag==HEX_ON)printf("\t%c=0x%08X\n",'a'+i,(BIGINT)reg[i]);elseprintf("\t%c=0%o\n",'a'+i,(BIGINT)reg[i]);}printf("--> ");}break;case 41:#line 100 "calc.y"{ for(i=0;i<26;i++)reg[i]=0;printf(">>All registers erased!\n-->");}break;case 42:#line 101 "calc.y"{printf(">>COMMANDS:\n");printf(">help: Display this help section.\n");printf(">clear: Clear the screen.\n");printf(">dec: Decimal mode to displaynumbers or registers.\n");printf(">hex: Hexadecimal mode to displaynumbers or registers.\n");printf(">oct: Octal mode to display numbersor registers.\n");printf(">list: List the values in the 26registers which are ranged from'a'/'A' to 'z'/'Z'.\n");printf(">erase: Reset all registers to 0.\n");printf(">exit: Quit this program.\n");printf("-->");}break;}/* Line 999 of yacc.c. */#line 1349 "y.tab.c"yyvsp -= yylen;yyssp -= yylen;YY_ST ACK_PRINT (yyss,yyssp);*++yyvsp = yyval;/* Now `shift' the result of thereduction. Determine what statethat goes to, based on the statewe popped back to and the rulenumber reduced by. */yyn = yyr1[yyn];yystate = yypgoto[yyn -YYNT OKENS] + *yyssp;if (0 <= yystate && yystate <=YYLAST && yycheck[yystate] ==*yyssp)yystate = yytable[yystate];elseyystate = yydefgoto[yyn -YYNT OKENS];goto yynewstate;/*------------------------------------.| yyerrlab -- here on detecting error |`------------------------------------*/yyerrlab:/* If not already recovering froman error, report this error. */if (!yyerrstatus){++yynerrs;#if YYERROR_VERBOSEyyn = yypact[yystate];if (YYPACT_NINF < yyn&& yyn < YYLAST){YYSIZ E_T yysize = 0;int yytype =YYTRANSLAT E (yychar);const char* yyprefix;char *yymsg;int yyx;/* Start YYX at -YYN ifnegative to avoid negative indexesinYYCHECK. */int yyx begin = yyn < 0 ?-yyn : 0;/* Stay within bounds ofboth yycheck and yytname. */int yychecklim =YYLAST - yyn;int yyxend =yychecklim< YYNT OKENS ? yychecklim :YYNT OKENS;int yycount = 0;yyprefix = ", expecting ";for (yyx = yyx begin; yyx< yyxend; ++yyx)i f (yycheck[yyx + yyn]== yyx && yyx != YYTERROR){yysize += yystrlen(yyprefix) + yystrlen (yytname[yyx]);yycount += 1;if (yycount == 5){yysize = 0;break;}}yysize += (sizeof ("syntaxerror, unexpected ")+ yystrlen(yytname[yytype]));yymsg = (char *)YYST ACK_ALLOC (yysize);if (yymsg != 0){char *yyp =yystpcpy (yymsg, "syntax error,unex pected ");yyp = yystpcpy (yyp,yytname[yytype]);if (yycount < 5){yyprefix = ",expecting ";for (yyx =yyx begin; yyx < yyxend; ++yyx)i f(yycheck[yyx + yyn] == yyx &&yyx != YYTERROR){yyp =yystpcpy (yyp, yyprefix);yyp =yystpcpy (yyp, yytname[yyx]);yyprefix = "or ";}}yyerror (yymsg);YYST ACK_FREE(yymsg);}elseyyerror ("syntax error;also virtual memory exhausted");}else#endif /* YYERROR_V ERBOSE */yyerror ("syntax error");}。

编译原理 简单计算器程序设计实验

编译原理 简单计算器程序设计实验

1.实验目的:用户可以直接输入表达式(没有空格),遇到等号后说明输入结束,输出运算结果,达到计算的目的。

2.实验要求:设计、实现一个简单的计算器程序。

3.实验环境:一台配置为1G的XP操作系统的PC机,myeclipse9.0.4.实验原理:用java语言编写界面和后台简单的计算处理。

5.软件设计与编程:首先编写好计算器各按键的布局和界面;编写好后台简单的计算事务处理程序;在上部的文本框中显示计算过程和结果。

对应源程序代码如下:package jisuanqi;import java.util.*;import java.awt.*;import java.awt.event.*;import javax.swing.*;import java.applet.*;public class Calculator extends JApplet implements ActionListener {boolean i=true;private JButton num0=new JButton("0");private JButton num1=new JButton("1");private JButton num2=new JButton("2");private JButton num3=new JButton("3");private JButton num4=new JButton("4");private JButton num5=new JButton("5");private JButton num6=new JButton("6");private JButton num7=new JButton("7");private JButton num8=new JButton("8");private JButton num9=new JButton("9");private JButton zuok=new JButton("(");private JButton youk=new JButton(")");private JButton dian=new JButton(".");private JButton NULL=new JButton("N");private JButton plu=new JButton("+");private JButton min=new JButton("-");private JButton mul=new JButton("x");private JButton div=new JButton("/");private JButton equ=new JButton("=");private JButton cle=new JButton("C");//清除private JTextField space=new JTextField(20);public void init(){JPanel text=new JPanel();text.setLayout(new FlowLayout());text.add(space);JPanel buttons=new JPanel();buttons.setLayout(new GridLayout(5,4)); buttons.add(num7);buttons.add(num8);buttons.add(num9);buttons.add(div);buttons.add(num4);buttons.add(num5);buttons.add(num6);buttons.add(mul);buttons.add(num1);buttons.add(num2);buttons.add(num3);buttons.add(min);buttons.add(num0);buttons.add(cle);buttons.add(NULL);buttons.add(plu);buttons.add(zuok);buttons.add(youk);buttons.add(dian);buttons.add(equ);(num9).addActionListener(this);(num8).addActionListener(this);(num7).addActionListener(this);(num6).addActionListener(this);(num5).addActionListener(this);(num4).addActionListener(this);(num3).addActionListener(this);(num2).addActionListener(this);(num1).addActionListener(this);(num0).addActionListener(this);(plu).addActionListener(this);(min).addActionListener(this);(mul).addActionListener(this);(div).addActionListener(this);(equ).addActionListener(this);(cle).addActionListener(this);(zuok).addActionListener(this);(youk).addActionListener(this);(dian).addActionListener(this);setLayout(new BorderLayout());add("North",text);add("South",buttons);space.setText("0");}public void actionPerformed(ActionEvent e) {if(e.getSource()==num9){if(i==true){space.setText("9");i=false;}else space.setText(space.getText()+'9'); }if(e.getSource()==num8){if(i==true){space.setText("8");i=false;}else space.setText(space.getText()+'8'); }if(e.getSource()==num7){if(i==true){space.setText("7");i=false;}else space.setText(space.getText()+'7'); }if(e.getSource()==num6){if(i==true){space.setText("6");i=false;}else space.setText(space.getText()+'6'); }if(e.getSource()==num5){if(i==true){space.setText("5");i=false;}else space.setText(space.getText()+'5'); }if(e.getSource()==num4){if(i==true){space.setText("4");i=false;}else space.setText(space.getText()+'4'); }if(e.getSource()==num3){if(i==true){space.setText("3");i=false;}else space.setText(space.getText()+'3'); }if(e.getSource()==num2){if(i==true){space.setText("2");i=false;}else space.setText(space.getText()+'2'); }if(e.getSource()==num1){if(i==true){space.setText("1");i=false;}else space.setText(space.getText()+'1');}if(e.getSource()==num0){if(i==true){space.setText("0");i=false;}else space.setText(space.getText()+'0');}if(e.getSource()==zuok){if(i==true){space.setText("(");i=false;}else space.setText(space.getText()+'(');} if(e.getSource()==youk){if(i==false)space.setText(space.getText()+')'); }if(e.getSource()==dian){if(i==false)space.setText(space.getText()+'.');}if(e.getSource()==plu){space.setText(space.getText()+'+');i=false;}if(e.getSource()==min){space.setText(space.getText()+'-');i=false;}if(e.getSource()==mul){space.setText(space.getText()+'*');i=false;}if(e.getSource()==div){space.setText(space.getText()+'/');i=false;}if(e.getSource()==equ){space.setText(String.valueOf(Calculator(space.getText())));i=true;}if(e.getSource()==cle){space.setText("0");i=true;}}public double Calculator(String f)//科学计算{int i=0,j=0;char c;StringBuffer s=new StringBuffer();s.append(f);s.append('=');String formula=s.toString();char[] anArray;anArray=new char[50];Stack<Character> mystack=new Stack<Character>();while(formula.charAt(i)!='='){c=formula.charAt(i);switch(c){case'(': mystack.push(new Character(c));i++;break;case')':while(mystack.peek().charValue()!='('){anArray[j++]=mystack.pop().charValue();}mystack.pop();i++;break;case'+':case'-':while(!mystack.empty()&&mystack.peek().charValue()!='(') {anArray[j++]=mystack.pop().charValue();}mystack.push(new Character(c));i++;break;case'*':case'/':while(!mystack.empty()&&(mystack.peek().charValue()=='*'||mystack.pee k().charValue()=='/')){anArray[j++]=mystack.pop().charValue();}mystack.push(new Character(c));i++;break;case' ': i++;break;default: while((c>='0'&&c<='9')||c=='.'){anArray[j++]=c;i++;c=formula.charAt(i);}anArray[j++]='#';break;}}while(!(mystack.empty()))anArray[j++]=mystack.pop().charValue();i=0;int count;double a,b,d;Stack<Double> mystack1 =new Stack<Double>(); while(i<j){c=anArray[i];switch(c){case'+':a=mystack1.pop().doubleValue();b=mystack1.pop().doubleValue();d=b+a;mystack1.push(new Double(d));i++;break;case'-':a=mystack1.pop().doubleValue();b=mystack1.pop().doubleValue();d=b-a;mystack1.push(new Double(d));i++;break;case'*':a=mystack1.pop().doubleValue();b=mystack1.pop().doubleValue();d=b*a;mystack1.push(new Double(d));i++;break;case'/':a=mystack1.pop().doubleValue();b=mystack1.pop().doubleValue();if(a!=0){d=b/a;mystack1.push(new Double(d));i++;}else{System.out.println("Error!"); }break;default:d=0;count=0;while((c>='0'&&c<='9')){d=10*d+c-'0';i++;c=anArray[i];}if(c=='.'){i++;c=anArray[i];while((c>='0'&&c<='9')){count++;d=d+(c-'0')/Math.pow(10,count); i++;c=anArray[i];}}if(c=='#')mystack1.push(new Double(d));i++;break;}}return(mystack1.peek().doubleValue());}}5.程序测试结果:。

科学计算器设计实现(编译原理课设)

科学计算器设计实现(编译原理课设)
{
cout<<"含有非法的字符!"<<endl;
returnfalse;
}
}
///////////////////////////////////////////////////////////////////
///检测括号是否匹配
for(intm=0; m<length; m++)
{
test = a[m];
//
//得到栈顶元素
//
voidGetTop(ElemType &e)
{
e =this->top->next->elem;
}
////////////////////////////////////////////////////////////////////////////////
//
//判断栈是否为空
top->elem =0;
}
////////////////////////////////////////////////////////////////////////////////
//
//使用析构函数销栈
//
~stack()
{
node <ElemType>*p =this->top;
while(p->next != NULL)
{
ischar++;
continue;
}
}
///符号数量少
if(isnumber > ischar+1)
#include <iostream>
#include <string.h>

词法分析器-计算器-设计与实现实验报告汇总

词法分析器-计算器-设计与实现实验报告汇总

辅导教师张静成绩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。

C++课程设计报告---计算器的设计与实现

C++课程设计报告---计算器的设计与实现

C++课程设计报告---计算器的设计与实现C++课程设计报告( 20 -- 20 年度第学期)计算器的设计与实现专业计算机科学与技术学生姓名班级学号指导教师完成日期C++课程设计报告(2011)目录1 概述 (3)1.1 课程设计目的 (3)1.2 课程设计内容 .................................................. 3 2 系统需求分析 ..................................................... 32.1 系统目标 ...................................................... 3 2.2 主体功能 ...................................................... 3 2.3 开发环境 ...................................................... 3 3 系统概要设计 ..................................................... 43.1 系统功能划分 .................................................. 4 3.2 系统流程图 .................................................... 5 4系统详细设计 ...................................................... 5 4.1 设计步骤 ...................................................... 5 4.2 界面设计 ...................................................... 7 4.2实现高级按钮控件类 ........................................... 10 5 测试 ............................................................ 11 5.1 测试方案 ..................................................... 11 5.2 测试结果 ..................................................... 11 6 小结 ............................................................ 12 参考文献 ......................................................... 14 附录 .......................................................... 15 附录1 源程序清单 . (15)C++课程设计报告(2011)计算器的设计与实现1 概述1.1 课程设计目的1、巩固并加深学生对C++语言程序设计知识的理解;2、培养学生面向对象的程序设计思想,使学生认识面向过程和面向对象两种设计方法的区别;3、进一步掌握和应用VC++ 6.0集成开发环境;4、提高运用C++语言解决实际问题的能力;5、初步掌握开发小型实用软件的基本方法,能独立设计、实现基本的MIS系统;6、掌握书写程序设计开发文档的能力(书写课程设计实验报告)。

基于编译原理的四则混合运算器的实现

基于编译原理的四则混合运算器的实现

基于编译原理的四则混合运算器的实现作者:秦飞舟来源:《电脑知识与技术·学术交流》2008年第15期摘要:计算机只能执行机器代码,只有专业程序人员才能较好地使用此类语言。

因此编译程序已成为计算机系统的最重要的系统程序之一。

本文主要通过对四则混合计算器的软件的设计分析讲述了编译程序的工作过程及具体实现。

关键词:四则混合计算器;词法分析;语法分析;LR分析;语义分析中图分类号:TP312 文献标识码:A文章编号:1009-3044(2008)15-2pppp-0cFour Items of Commixture Arithmetic Device RealizationQIN Fei-zhou(Academy of Physics and Electricity Information,University of Ningxia,Yinchuan 750021,China)Abstract:The computer can only carry out the machine code,only specialized procedure personnel could use this kind of language well.So the compiler has already become one of the most important systematic procedures of the computer system. Mainly through mix to four fundamental rules design of software of calculator is it tell working course and concrete to realize of compiler to analyse this text.Key words:The four fundamental operations of arithmetic blends a calculator;Lexical analysis;Grammatical analysis;LR analysis;Semantic analysis我们每个人都使用过计算器,专用的计算器都是一个现成的器件,是由运算芯片完成运算功能的。

编译原理课程设计-基于表达式计算器

编译原理课程设计-基于表达式计算器

编译原理课程设计-基于表达式计算器**工程学院编译原理课程设计课程设计题目 :表达式计算器姓名 :***院,系, :计算机科学与工程学院专业班级 :计算机科学与技术084班学号 ,200810214415 指导教师 :***设计日期 :2010 年 12 月26日目录表达式计算器 ..................................................................... .................... 1 1. 需求分析 ..................................................................... . (1)1.1. 总述 ..................................................................... ..................... 1 2. 概要设计 ..................................................................... . (1)2.1. 开发环境 ..................................................................... . (1)2.2. 总体设计 ..................................................................... . (2)2.2.1. 模块结构图 ......................................................................22.2.2. 模块说明 ..................................................................... .. (2)2.2.3. 界面设计 ..................................................................... ..... 3 3. 详细设计 ..................................................................... . (4)3.1. 词法分析模块: .................................................................... (4)3.1.1. 词法分析简介: (4)3.1.2. 词法分析模块的设计及实现 (4)3.2. 语法分析模块 ..................................................................... . (11)3.2.1. 语法分析简介 (11)3.2.2. 语法分析器的实现 (11)3.3 文法分析 ..................................................................... .. (19)..1 文法分析器生成工具yacc (19)4. .测试分析 ..................................................................... . (21)I5 课程总结 ..................................................................... .. (24)6 .参考文献 ..................................................................... . (25)II表达式计算器1. 需求分析1.1. 总述计算器是我们经常使用的小工具,它能帮我们对数据进行有效的运算,如通过四则运算能实现对输入数据的加减乘除。

编译原理课程设计计算器

编译原理课程设计计算器

编译原理课程设计 计算器一、课程目标知识目标:1. 理解编译原理的基本概念,掌握计算器程序的基本结构和组成;2. 学会使用指定编程语言(如C、Java等)编写简单的计算器程序;3. 掌握计算器的词法分析、语法分析、语义分析及中间代码生成的基本方法;4. 了解编译过程中可能出现的错误类型及相应的调试方法。

技能目标:1. 能够运用所学知识独立设计并实现一个具备基本功能的计算器程序;2. 能够分析计算器程序的执行过程,进行性能优化;3. 能够运用调试工具对计算器程序进行调试,找出并修复错误;4. 提高团队协作能力,通过与同学合作完成复杂计算器程序的设计与实现。

情感态度价值观目标:1. 培养学生对编译原理的兴趣,激发学生学习编程的热情;2. 培养学生的创新意识和问题解决能力,使学生能够主动探索新知识;3. 培养学生良好的编程习惯,注重代码规范和注释;4. 强化学生的团队合作意识,提高沟通与协作能力。

本课程针对高年级学生,课程性质为理论与实践相结合。

在分析课程性质、学生特点和教学要求的基础上,将课程目标分解为具体的学习成果,以便后续的教学设计和评估。

通过本课程的学习,学生将掌握编译原理的基本知识,具备编写和调试计算器程序的能力,并在团队合作中提高沟通与协作能力。

文本教学一、教学内容根据课程目标,本章节教学内容主要包括以下五个部分:1. 编译原理基本概念:介绍编译器的作用、编译过程、编程语言的分类等基本概念,让学生对编译原理有一个整体的认识。

2. 计算器程序结构:分析计算器程序的基本组成,包括词法分析、语法分析、语义分析、中间代码生成、目标代码生成等模块,为学生设计计算器程序提供理论支持。

3. 编程语言语法:结合课程所选编程语言,讲解基本语法和数据类型,使学生能够运用所学知识编写计算器程序。

4. 计算器程序设计与实现:引导学生根据编译原理的基本方法,设计并实现一个具备基本功能的计算器程序,包括加减乘除等运算。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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对象。

相关文档
最新文档