编译器指令重排
问候,
介绍文章的这一部分晚了一个星期。 我为此表示歉意; 我的借口是:
bizzy,bizzy,bizzy; 我参加了一门不错的课程,我不得不讲一点,
根本没有时间写作。
我们已经走了很长一段路; 先前的文章讨论了以下方面
的编译器:
1:概述,概述编译器和
他们编译的语言;
2:负责转换字符的令牌生成器(或词法分析器)
输入流到令牌输入流;
3:形式语法,描述一种(编程)语言的语法,并且
形成实施语言解析器的指南;
4:编译器的多个部分所需的所有必要簿记; 的
表格定义函数,运算符和其他预定义符号;
5:解析器要注意令牌流是否遵循某种语法。
解析器与编译器的代码生成器部分紧密合作。
6:执行或评估生成的指令序列的解释器。
使用说明本文的最后一部分讨论了说明本身。 每一个
指令实现此接口:
public interface Instruction extends Serializable {
public void execute(Interpreter interpreter) throws InterpreterException;
public void initialize(String token, int arity);
}
第二种方法仅在指令为
建造。 第一种方法由解释器调用。 就这些了
解释器感兴趣的是:按以下顺序调用每个指令:
说明。
这是指令类层次结构的顶部:
Instruction
|
+-------+- AbstractInstruction
|
+-------+- AbstractFunctionInstruction
| |
| +----------- FunctionInstruction
| |
| +----------- UserInstruction
|
+--------- QuoteInstruction
AbstractInstruction类实现特定对象的名称和属性
指令。 指令的均等性等于
该特定指令占用的堆栈; 例如'+'的组合
运算符等于2,名称等于“ +”。
在AbstractInstruction下方,有两种指令的子类型:
AbstractFunctionInstruction和QuoteInstruction。 第一个子类
实现普通的内置函数以及用户定义的函数。
QuoteInstruction实现特殊的函数类型指令。 一个例子
这样的指令是IfInstruction:Arity等于3及其名称
是“如果”。 允许我们键入以下内容:
if (x, y, z)
如果表达式“ x”不等于零,则“ if”函数的值等于
'y',否则该值等于'z'。 如您先前所读
本文的一部分,将生成的x,y和z指令传递给
IfInstruction原样,即'if'指令传递了
组成表达式“ x”的指令要执行的解释器。
如果堆栈的顶部元素不为零,则“ y”的指令序列
传递给解释器,否则用于表达的指令序列
“ z”被传递给解释器。
FunctionInstruction是普通内置函数的基类
例如'sin','cos','log'等。UserInstruction处理所有用户定义的
功能。
功能运算符实现为FunctionInstructions。 没什么奇怪的
关于它; 比较一下:
add(x, y)
x+y
只是源代码中的符号有点“奇怪”,即“ +”
运算符兼作“添加”功能; 两者是相同的。
函数从堆栈中弹出其参数并计算其值。 对于“ +”
运算符将添加操作数,并将结果推回堆栈中。 对于,
例如,“正弦”函数,从堆栈中弹出一个操作数,正弦为
计算并把结果再次推回堆栈。
与其在每个类中实现所有的推送和弹出,
AbstractFunctionInstruction会处理所有这一切。 查看随附的源代码
与本文的前一部分。
实现了以下功能:
+-! (一元运算符)
<<= ==!=> =>
+-
* /
^
罪恶谭
经验日志
最大最小吸收
所有功能都具有众所周知的语义。
堆栈功能除了这些“正常”功能外,还可以使用其他功能
显式操纵数据栈。
实现了以下功能:
arg(n):将第n个元素从堆栈的顶部移到顶部;
top(n):将第n个元素从堆栈的顶部复制到顶部;
clear():清除整个堆栈;
depth():推送堆栈上堆栈元素的数量。
您可以使用附件中提供的软件来使用这些功能
本文前面的部分。 如果破坏堆栈,则不会造成任何危害,即
解释器发出错误的栈信号并抛出异常
被打印,执行就停止了。 如果要使用Interpreter类
在您自己的软件中,您可以打印一条消息并开始评估另一个序列
指令。 随意玩。
清单我们的小语言支持简单的列表,例如'+'功能/操作符可以
在简单的双操作数上调用,例如“ 3 + 4”,但其一个或两个
操作数也可以是列表。 如果一个操作数是一个列表,则所有列表都具有
简单的意思是:一维相同长度的列表; 这里
以下是一些示例:
{3, 4} + 5 // {8, 9}
{3, 4} + {5, 6} // {8, 10}
{3, 4} + {5, 6, 7} // error
{3, 4} + {5, {6, 7}} // error
min({3, 6}, {5, 4}) // {3, 4}
max({3, 6}, 5) // {5, 6}
AbstractFunctionInstruction负责处理所有这一切;
如果至少
操作数是一个列表,然后所有表示该函数的操作数的列表
需要简单且长度相同。 AbstractFunctionInstruction通过
函数的双操作数并收集结果。 最终它建立
再次列出结果。
一些函数绕过该机制,即它们自己处理列表操作数。
还记得“ listfunc”保留字吗? 使用“ listfunc”定义的用户功能
标记保留字,以便绕过上述机制。
还有一些内置函数可以处理列表:
append(x,y)//将y附加到x
aslist(n)//将前n个堆栈元素存储在列表中
concat(x,y)//将x和y合并到一个新列表中
head(x)//列表x的第一个元素
tail(x)//除列表x的第一个元素外的所有元素
join(x,y)//加入两个列表x和y
size(x)//列表x中的元素数
同样,请随意使用这些功能。 好有趣。 看看你能找到什么
append,concat和join确实可以做到以及它们之间的区别。
报价说明上面已经提到了QuoteInstructions之一; 有三种
这些定义的指令中:
if(x,y,z)//如果(x)则y else z
while(x,y)// 0或y的最后结果
generate(x,y)//而(x)将y附加到列表
请尝试使用随附的软件(请参阅上一篇文章)
如果您喜欢冒险,请使用已经实现的类作为蓝图
为您自己的功能。 如果不是冒险的话。 别忘了改变
.properties文件。
结束语鉴于这篇大型文章中描述的所有软件,轻而易举地
实施一个表达式评估器。 只需几行代码即可完成
工作。 这个口译员不仅可以做很多,但我留给你
想像力想出可以将这个小系统
辛苦了 即使只是打印生成的指令(尝试!)也可以
是一个教育经历:您将免费看到后缀翻译的中缀。
这是评估器方法:
// evaluate the expression, throws InterpreterExcetpion if anything's wrong
public double evaluate(String expression) throws InterpreterException {
// parse the string
Code code= new Parser().parse(new StringReader(expression));
// do the evaluation and get the stack top
Value value= new Interpreter().executeSub(code);
// convert the value back to a double
return value.getDbl();
}
我希望人们实际上已经阅读了这一切。
如果您这样做:恭喜,您
一定学到了很多东西,我希望附带的软件可以是任何
为您使用。
下一个技巧将涉及文本处理和查询。 我其实还没有
实施任何操作,但我会提出一些建议。
亲切的问候,
乔斯
翻译自: https://bytes.com/topic/java/insights/672530-compilers-7-instructions
编译器指令重排