// 来自龙书第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

代码有两点简化:

  1. 将rest函数的尾递归替换为迭代过程
  2. 将修改后的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实现版的更多相关文章

  1. 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——3 计算4个函数

    整个引擎代码在github上,地址为:https://github.com/sun2043430/RegularExpression_Engine.git nullable, firstpos, la ...

  2. 编译原理_P1004

    龙书相关知识点总结 //*************************引论***********************************// 1. 编译器(compiler):从一中语言( ...

  3. Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

    catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...

  4. 龙书(Dragon book) +鲸书(Whale book)+虎书(Tiger book)

    1.龙书(Dragon book)书名是Compilers: Principles,Techniques,and Tools作者是:Alfred V.Aho,Ravi Sethi,Jeffrey D. ...

  5. Go 编译原理实现计算器(测试驱动讲解)

    本文不需要你掌握任何编译原理的知识. 只需要看懂简单的golang语言即可, 完整的代码示例在GIT, 代码是从writing an interpreter in go这本书抽取了简单的部分出来, 如 ...

  6. 学了编译原理能否用 Java 写一个编译器或解释器?

    16 个回答 默认排序​ RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...

  7. 编译原理之正则表达式转NFA

    本文转载自http://chriszz.sinaapp.com/?p=257 输入一个正则表达式,输出一个NFA. 我的做法:输入一个字符串表示正则,输出则是把输出到一个.dot文件中并将dot文件编 ...

  8. Stanford公开课《编译原理》学习笔记(1~4课)

    目录 一. 编译的基本流程 二. Lexical Analysis(词法分析阶段) 2.1 Lexical Specification(分词原则) 2.2 Finite Automata (典型分词算 ...

  9. Stanford公开课《编译原理》学习笔记(2)递归下降法

    目录 一. Parse阶段 CFG Recursive Descent(递归下降遍历) 二. 递归下降遍历 2.1 预备知识 2.2 多行语句的处理思路 2.3 简易的文法定义 2.4 文法产生式的代 ...

随机推荐

  1. centos7查看网卡UUID

    https://blog.csdn.net/kepa520/article/details/50222049 查看网卡UUID nmcli con show 查看mac地址 nmcli device ...

  2. 个人作业4——alpha阶段个人总结

    一.个人总结 类型 具体技能和面试问题 现在的回答(大三) 语言 拿手的计算机语言(偏web前端,PC/Mobile App) java 语言 拿手的计算机语言(偏后端,数据处理,网站后台,机器学习等 ...

  3. ThinkPHP5 添加多个文字水印及疑难解答

    public function imageload() { $imgpath = ROOT_PATH . 'public' . DS . 'static' . DS . 'www' . DS . 'i ...

  4. Android的几种Manager

    电话管理器TelephoneManager 第一个实例是获取网络和SIM卡信息:界面是一个列表,这里省略,Java代码如下: public class MainActivity extends Act ...

  5. MySQL中dblink的实现(通过federated引擎实现)

    最近项目中涉及MySQL数据库视图的创建,需要整合两个位于不同服务器上数据库的内容,就遇到了远程访问数据库的问题.在oracle中可以通过dblink来实现跨本地数据库来访问另外一个数据库中的数据.通 ...

  6. WebSocket(一)-RFC6455

    1.官方在线 本地下载 参考翻译:gitbook

  7. 2018-2019-2 网络对抗技术 20165336 Exp2 后门原理与实践

    2018-2019-2 网络对抗技术 20165336 Exp2 后门原理与实践 1.基础问题回答 (1)例举你能想到的一个后门进入到你系统中的可能方式? 下载自己不熟悉的软件时含有病毒. 网络钓鱼, ...

  8. Vue keep-alive如何实现只缓存部分页面

    prop: include: 字符串或正则表达式.只有匹配的组件会被缓存. exclude: 字符串或正则表达式.任何匹配的组件都不会被缓存. 在2.1.0版本Vue中 常见用法: // 组件 exp ...

  9. 写一个方法,用于解读 url 后面的请求参数,最终得到 {"a":2,"b":3,"c":4};

    function getUrlParams(url){ let searchParam = url.split("?")[1]; let searchItemParams = se ...

  10. warning: a non-numeric value encountered in line *的解决方法

    今天ytkah在调试项目的时候出现了一个警告warning: a non-numeric value encountered in line 694,查看php官方文档,上面解释说在使用(+ - * ...