// 来自龙书第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. 我了解到的新知识之----遇到路由器DNS被篡改我该怎么办?

    最近一则新闻让我不得不开始重视家中一直沉默在角落里路由器了. http://www.21ic.com/tougao/article/8346.html 于是立刻搜索了一些关于如何检查DNS地址是否被修 ...

  2. 尽量避免把弹窗加在window上,可以考虑把弹窗封装到控制器里面

    封装自定义弹窗,一般来说有两种选择: 在[[[UIApplication sharedApplication] delegate] window]上add自定义view: present一个模态Con ...

  3. python 包下载地址

    https://www.lfd.uci.edu/~gohlke/pythonlibs/

  4. 存储过程中拼接sql并且参数化

    ALTER PROCEDURE [dbo].[proc_test] ( ) = ' order by id desc ', @userid int, @stime datetime, @etime d ...

  5. vue + ts @Prop boolean 问题

    假设btn组件有一prop属性radio,声明如下 @Prop({ default: false }) radio!: boolean; 在组件传递 <btn radio /> 此时的 r ...

  6. 如何优化 ThreadPoolExecutor

    一.想让线程池在初始化时就干活,而不是等到第一次提交任务时才创建线程,该怎么做? /** * Starts all core threads, causing them to idly wait fo ...

  7. Django---路由、配置和静态文件简介

    路由.配置文件.静态文件 一.url配置 二.配置文件 三.静态文件 回到顶部 一.url配置 1.url的配置过程 2.注意点 Django默认url配置风格,实在用户访问的路径后面加 \ 用户在主 ...

  8. 某里巴巴Java工程师常规面试题以及解答

    从HR弄来的P6-P7的JAVA工程师题目,分享给大家 1 Spring AOP和IOC的实现方法 http://blog.csdn.net/tarena_lixy/article/details/7 ...

  9. struts 2.5配置

    1.jar包的变动 必需jar包,旧版本: 必需jar包,新版本: 在struts-2.5.16版本的lib目录下没有xwork-core的jar包,原因是被合并到struts-core这个jar里了 ...

  10. MongoDB系列----mongostat

    mongostat是mongodb自带的监测工具,位于bin目录下.能用于实时监测mongodb的运行状态.在mongodb运行出现问题需要检测的时候应该优先考虑使用mongostat查看mongo运 ...