编译原理 #03# 龙书中缀转后缀JS实现版
// 来自龙书第2章2.5小节-简单表达式的翻译器
笔记
既然是语法制导翻译(Syntax-directed translation),那么最重要的东西当然是描述该语言语法的文法,以下为中缀表达式文法(仅由+-以及0~9的数字构成):
expr -> expr + term | expr - term | term
term -> ~9的数字
接下来考虑如何利用该文法将原语言转化为后缀形式,此时可以脑补一下该文法的语法分析树(parse tree),例如:

严格来说,语法分析树是相对于某特定终结符号串生成的,叶子结点必须是终结符号,但是方便起见就省略了。expr1是expr的某个实体,便于和它的父结点区分。如果有能力构造这棵树的话,只需按照某种遍历求值顺序,很容易可以得到“expr->expr+term”到其后缀形式的语法制导定义(syntax-directed definition):
expr.后缀形式 -> expr1.后缀形式 term.后缀形式 +
龙书里把这种简单形式的语法制导定义称为简单语法制导定义(simple syntax-directed definition)。
一个语法制导定义把①每个文法符号和一个属性集合相关联,例如这里把expr和属性“后缀形式”相关联,并且把②每个产生式和一组语义规则(semantic rule)相关联,例如把“expr->expr+term”和“expr.后缀形式 -> expr1.后缀形式 term.后缀形式 +”相关联。
依据上面的语法制导定义我们可以得到一个语法制导翻译方案( syntax-directed translation scheme),也就是在文法产生式中附加一些程序片段来描述翻译结果的表示方法,被嵌入到产生式体中的程序片段称为语义动作(semantic action):
expr -> expr1 + term {print('+')}
term -> 数字 {打印该数字}
但是这个语法制导翻译方案没法直接写成代码,因为会发生左递归的问题:
function expr() {
expr()
...
}
消除左递归(该过程需特别小心!详见书)得到:
expr -> term rest
rest -> + term {print('+')} rest
代码有两点简化:
- 将rest函数的尾递归替换为迭代过程
- 将修改后的rest函数并入expr函数
截图与代码

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title></title>
<link href="https://fonts.googleapis.com/css?family=Noto+Serif+SC" rel="stylesheet">
<style>
main {
/*对子元素开启弹性布局*/
display: flex;
/*弹性元素在必要的时候换行*/
flex-wrap: wrap;
/*将弹性元素居中*/
justify-content: center;
} textarea,
button {
font-family: 'Noto Serif SC', STFangSong, serif;
font-size: 17px;
}
</style>
</head> <body>
<main>
<textarea name="input" rows="20" cols="40"></textarea>
<textarea name="output" rows="20" cols="40"></textarea>
<button name="execute">Execute</button>
</main> <script>
let inputBox = document.querySelector("textarea[name=input]");
let outputBox = document.querySelector("textarea[name=output]");
let btnExecute = document.querySelector("button[name=execute]"); btnExecute.addEventListener("click", event => {
startParsing(inputBox.value);
}); function startParsing(s) {
str = s;
cur = 0;
result = "";
expr();
outputBox.value = result;
} function expr() {
term();
while (true) {
if (str[cur] == '+') {
match('+');
term();
result += '+';
} else if (str[cur] == '-') {
match('-');
term();
result += '-';
} else {
return;
}
}
} function term() {
if (/[0-9]/.test(str[cur])) {
result += str[cur];
match(str[cur]);
} else {
report("存在语法错误,字符位置为:" + cur);
}
} function match(ch) {
if (cur < str.length && str[cur] === ch) ++cur;
else report("存在语法错误,字符位置为:" + cur);
} function report(s) {
outputBox.value = s;
throw new Error(s);
}
</script>
</body> </html>
编译原理 #03# 龙书中缀转后缀JS实现版的更多相关文章
- 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——3 计算4个函数
整个引擎代码在github上,地址为:https://github.com/sun2043430/RegularExpression_Engine.git nullable, firstpos, la ...
- 编译原理_P1004
龙书相关知识点总结 //*************************引论***********************************// 1. 编译器(compiler):从一中语言( ...
- Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用
catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...
- 龙书(Dragon book) +鲸书(Whale book)+虎书(Tiger book)
1.龙书(Dragon book)书名是Compilers: Principles,Techniques,and Tools作者是:Alfred V.Aho,Ravi Sethi,Jeffrey D. ...
- Go 编译原理实现计算器(测试驱动讲解)
本文不需要你掌握任何编译原理的知识. 只需要看懂简单的golang语言即可, 完整的代码示例在GIT, 代码是从writing an interpreter in go这本书抽取了简单的部分出来, 如 ...
- 学了编译原理能否用 Java 写一个编译器或解释器?
16 个回答 默认排序 RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...
- 编译原理之正则表达式转NFA
本文转载自http://chriszz.sinaapp.com/?p=257 输入一个正则表达式,输出一个NFA. 我的做法:输入一个字符串表示正则,输出则是把输出到一个.dot文件中并将dot文件编 ...
- Stanford公开课《编译原理》学习笔记(1~4课)
目录 一. 编译的基本流程 二. Lexical Analysis(词法分析阶段) 2.1 Lexical Specification(分词原则) 2.2 Finite Automata (典型分词算 ...
- Stanford公开课《编译原理》学习笔记(2)递归下降法
目录 一. Parse阶段 CFG Recursive Descent(递归下降遍历) 二. 递归下降遍历 2.1 预备知识 2.2 多行语句的处理思路 2.3 简易的文法定义 2.4 文法产生式的代 ...
随机推荐
- Selenium 3----定位一组元素+多表单切换+多窗口切换
定位一组元素 和定位单个元素类似,WebDriver提供了8种用于定位一组元素的方法.定位一组元素的方法与定位单个元素的方法类似,唯一的区别是在单词element后面多了一个s表示复数. find_e ...
- 源码包安装php7.2
含有的命令:yum,wget,tar,./configure,make,cp,ln,source,php -v ==安装== [root@ycj ~]# yum -y install libxml2 ...
- kettle获取系统时间
Date.prototype.Format = function (fmt) { //author: meizz var o = { "M+": this.getMonth() + ...
- Python——开发一个自动化微信投票器【附代码实例方法】
一个研究Python实践,最近研究一个投票的东东,主要是想测试利用Python实现刷微信投票. 本文纯粹为了记录一下 webdriver直接操作页面按钮的方法: #!/usr/bin/python # ...
- k8s-No.2-pod学习
本章目录 pod结构图 pod语法及参数说明 pod声明周期 一 pod结构图 大部分情况下,Openshift中的Pod只是容器的载体,通过Deployment.DaemonSet.RC.Job. ...
- leetcode 之 Two Sum II - Input array is sorted c++
class Solution { public: vector<int> twoSum(vector<int>& numbers, int target) { int ...
- JVM深入:JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)(转)
转载自:https://www.cnblogs.com/yulei126/p/6777323.html 1.背景 2.为什么废弃永久代(PermGen) 3.深入理解元空间(Metaspace) 4. ...
- Oracle SQL 部分特殊字符转义及escape的用法
在处理sql时,遇到insert 或update 的参数中含有特殊字符“&”,下划线“_”, 单引号" ' "等时,要做转义处理. 例:插入特殊字元'&' upda ...
- JDK丨WIN10配置JDK1.8 (解决javac不是内部或外部命令,也不是可运行的程序或批处理文件)
1.下载JDK,安装. 2.配置JDK. (右键我的电脑 - 属性 - 高级系统设置 - 环境变量.) 2.1 添加系统变量JAVA_HOME 变量名:JAVA_HOME 变量值:C:\Program ...
- CarbonData-1:common
最近公司需要对CarbonData进一步应用,或许封装进产品,或许是为了解析CarbonData元数据,于是开始预研CarbonData,下面将保持每天一篇以上的阅读CarbonData源码博客,由于 ...