我有兴趣通过实现基于堆栈的编程语言来扩展我的计算机编程知识。我正在寻求从哪里开始的建议,因为我打算让它具有类似“pushint 1
" 会将值为 1 的整数推送到堆栈顶部,并通过诸如 " 之类的标签进行流量控制L01: jump L01:
".
到目前为止,我已经实现了我想要的语言的 C# 实现(想要链接到它,但 IDEOne 被阻止),但它非常混乱,需要优化。它将输入转换为 XML,然后对其进行解析。我的目标是使用较低级别的语言(可能是 C/C++),但我的问题是实现一个可以容纳各种数据类型并且没有固定大小的堆栈。
最终我还想实现数组和函数。此外,我认为我需要一个更好的词法分析器,我想知道解析树对于这种简单的语言是否是一个好主意。
欢迎任何建议/批评,请考虑到我对编程仍然相当陌生(我最近刚刚完成 AP CompSci I)。此外,欢迎链接到基于开源堆栈的语言。
这是一个我想尝试解释/编译的基本程序(其中[this is a comment]
):
[Hello World!]
pushchar '\n'
pushstring "Hello World!"
print
[Count to 5 and then count down!]
pushint 1
setlocal 0
L01:
pushchar '\n'
getlocal 0
print [print x + '\n']
getlocal 0
increment
setlocal 0 [x = x + 1]
pushint 5
getlocal 0
lessthan [x < 5]
iftrue L01
L02:
pushchar '\n'
getlocal 0
print [print x + '\n']
getlocal 0
decrement
setlocal 0 [x = x - 1]
pushint 0
getlocal 0
greaterthan [x > 0]
iftrue L02
预期输出为:
Hello World!
1
2
3
4
5
4
3
2
1
基于堆栈的语言,例如Factor http://factorcode.org/具有以下语法:
2 3 + 5 - print
这相当于以下 C 风格代码:
print(2 + 3 - 5);
使用基于堆栈的语言的优点是实现起来很简单。此外,如果该语言使用逆波兰表示法 http://en.wikipedia.org/wiki/Reverse_Polish_notation,就像大多数基于堆栈的语言一样,那么您所需要的一切前端 http://en.wikipedia.org/wiki/Compiler#Front_end你的语言是一个词法分析器。您不需要将标记解析为语法树,因为只有一种方法可以解码标记流。
您试图创建的不是基于堆栈的编程语言,而是基于堆栈的虚拟机 http://en.wikipedia.org/wiki/Comparison_of_application_virtual_machines。应用程序虚拟机可以是基于堆栈 http://en.wikipedia.org/wiki/Stack_machine or 基于寄存器 http://en.wikipedia.org/wiki/Register_machine。例如,Java虚拟机 http://en.wikipedia.org/wiki/Java_Virtual_Machine是基于堆栈的。它执行Java字节码 http://en.wikipedia.org/wiki/Java_bytecode(这就是您正在创建的内容 - 虚拟机的字节码)。然而,编译为该字节码的编程语言(例如 Java、Erlang、Groovy 等)不是基于堆栈的。
您尝试创建的内容就像您自己的虚拟机的汇编级语言,它恰好是基于堆栈的。话虽这么说,这样做相当容易——基于堆栈的虚拟机更容易实现基于寄存器的虚拟机。同样,您所需要的只是一个词法分析器,例如flex http://github.com/westes/flex。这是一个使用 JavaScript 编写的小示例,使用名为lexer https://github.com/aaditmshah/lexer:
var program = "[print(2 + 3)]";
program += "\n push 2";
program += "\n push 3";
program += "\n add";
program += "\n print";
lexer.setInput(program);
var token;
var stack = [];
var push = false;
while (token = lexer.lex()) {
switch (token) {
case "NUMBER":
if (push) stack.push(lexer.yytext);
else alert("Unexpected number.");
break;
case "ADD":
if (push) alert("Expected number.");
else stack.push(stack.pop() + stack.pop());
break;
case "PRINT":
if (push) alert("Expected number.");
else alert(stack.pop());
break;
}
push = token === "PUSH";
}
<script src="https://rawgit.com/aaditmshah/lexer/master/lexer.js"></script>
<script>
var lexer = new Lexer;
lexer.addRule(/\s+/, function () {
// matched whitespace - discard it
});
lexer.addRule(/\[.*\]/, function () {
// matched a comment - discard it
});
lexer.addRule(/\d+/, function (lexeme) {
this.yytext = parseInt(lexeme);
return "NUMBER";
});
lexer.addRule(/push/, function () {
return "PUSH";
});
lexer.addRule(/add/, function () {
return "ADD";
});
lexer.addRule(/print/, function () {
return "PRINT";
});
</script>
这真的很简单。您可以摆弄该程序并根据您的需要进行修改。祝你好运。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)