实现自己的脚本语言ngscript之二:语法分析
ngscript的语法分析使用的是我自己的语法分析工具parseroid。与常用cc工具(yacc、bison、javacc、antlr、etc…)不同的是,parseroid生成的不是语法分析器的源程序,而是一个parser对象,直接可以用来执行parsing。也就是说,可以由BNF在执行阶段动态生成parser。
生成parser的action table运算量还是有点大,所以在新版的parseroid里面table改成了serializable的,可以缓存下来免去生成table的过程。
实现parseroid
文法描述
parseroid使用LALR(1)文法。
parseroid使用的文法描述文件是这个样子
//starter symbol
%start <program>;
%array <statements> <param_list> <params>;
%equiv <expr> <expr1> <expr2> <expr3> <expr4> <expr5> <expr6> <expr7> <expr8> <nullable_expr>;
%filter semicolon comma;
<program> ::= <statements>;
//----------------------------------------------------------------------------
//statements is a collection of statement;
<statements> ::= NULL;
<statements> ::= <statement> <statements>;
//省略一些
<throw_exception> ::= throw <expr> semicolon => <expr>;
//再省略一些
%开头的是注记,有这几种
%start 指定一个起始符
%equiv 标记等价类,在生成语法树之后的reduce过程中,会把等价类合并
%filter 也是在reduce过程中,会把这些节点去掉
=> 标记的用处是在规约生成语法树的时候调整AST,如这句
<throw_exception> ::= throw <expr> semicolon => <expr>;
这句的意思是用throw <expr> semicolon的结构规约到<throw_exception>,但是只保存<expr>这个元素,主要是为了后面处理语法树方便和看起来更加顺眼……
实现
LALR(1)的具体细节书本上都有,就不再阐述了。
错误恢复
parseroid使用error符号错误恢复。
具体做法是写这样的产生式
<statements> ::= error semicolon <statements>;
效果是,在遇到statements中的错误之后,会把错误部分parsing为一个error节点,然后同步到semicolon的位置继续parsing。
具体过程抄一段书
1.不断的弹出栈顶,直到一个特定的状态,在该状态中error符号的动作为移进。
2.移进error符号
3.不断丢弃输入符号,直到一个特定的向前查看符号,它在当前状态,对应一个非出错的动作。
4.重新开始正常分析
语法树简化
- 合并等价类
- 删除无用的嵌套
- 删除不必要的节点
合并等价类是因为在parseroid的文法描述中,没有显式指定算符的优先级,需要使用产生式的层次来表现。
于是就有很多<expr1> <expr2>这种东西,但是他们实质上都可以当成expr来处理。
无用的嵌套是因为在<expr1>这种化为<expr>之后,可能出现如<expr> -> <expr> -> number 这种,也是可以简化的。
不必要的节点,就是左括号右括号这种。
parseroid源代码在这里
https://github.com/wssccc/parseroid.git
后面我会用lexeroid和parseroid实现ngscript的解析器。
一些分析方法的介绍
语法分析的方法有很多,简单介绍一下。
SLR(1)
编译原理的大作业就是实现SLR(1),可以处理这样的文法
S-># Ee #
Ee->Ee + Ti|Ee - Ti|Ti
Ti->Ti * Ff|Ti / Ff|Ff
Ff->( Ee )|d
Ff->sin Ff
Ff->cos Ff
当时觉得只要文法改改就能用,后来真正用的时候才发现是个坑……
书上是把它当过渡方法来讲的
Parser组合子
最开始知道这个是在
我也用Java实现了一个,因为Java没有lambda,硬是用匿名类整了出来。也是CPS的,带错误恢复。
运行起来大概是这样
不过解析器组合子的缺点也很明显,就是太难调试了。而且文法是用代码的形式在程序中描述的,太复杂之后我就被绕晕了 = =
LL(1)
LL(1)应该算是比较容易实现的,不过需要对文法做一些调整,消除左递归,提取左公因式什么的,后来写到二元运算符的文法我还是觉得LL(1)不能忍。
LALR(1)
书上介绍分析方法的顺序LALR(1)一般是排在最后的,按这种设定应该是这个最靠谱了。
附一张图:
实现自己的脚本语言ngscript之二:语法分析的更多相关文章
- 实现自己的脚本语言ngscript之零
正式开始介绍前先扯点没用的. 从小玩basic长大的小朋友大多有一个梦想,就是自己实现一个basic解释器. 不过这里我实现的不是basic,而是一个语法和功能类似javascript的东西. 暂且称 ...
- 实现自己的脚本语言ngscript之三:语法设计
这是第四篇了,之所以隔了这么久才写,一方面是因为最近开始实习了,另一方面是因为设计语法真是要考虑很多东西. 于是我去读了这本书,里面实现了两种语言,一种跟js差不多语法,用ast解释执行:另一种语法类 ...
- JavaScript脚本语言基础(二)
导读: JavaScript条件语句 JavaScript循环语句 JavaScript网页中错误捕获 JavaScript的Break和Continue命令 JavaScript的转义字符 1.Ja ...
- 实现自己的脚本语言ngscript之四:代码生成
最近的进度 ngscript测试代码 function c1(a, b, c, d) { this.a = 1; this.b = new array(); this.b[0] = 1; this.b ...
- 实现自己的脚本语言ngscript之一:词法分析
正则表达式的理论基础可以参考装配脑袋的 这个 自己动手开发编译器(二)正则语言和正则表达式 这个 自己动手开发编译器(三)有穷自动机 还有这个 自己动手开发编译器(四)利用DFA转换表建立扫描器 如果 ...
- 【程序员技术练级】学习一门脚本语言 python(二)遍历本地文件系统
这篇将讲述怎么使用python来遍历本地文件系统,并把文件按文件大小从小到大排序的一个小例子 在这个例子中,主要会用到python内置的和OS模块的几个函数: os.walk() : 该方法用来遍历指 ...
- 脚本语言:Xmas(二)
本篇,来谈谈类型系统,以及部分与垃圾收集器相关的内容. 一.基本类型 Xmas的基本类型:Null.Boolean.Label.String.Ref.Function.Integer.Float.De ...
- 全栈工程师之路(二)—— JavaScript(网页前端脚本语言)
javascript 是可以运行在网页前端的脚本语言,可以基于 html 之上实现更丰富的交互(网页内容的交互显示).异步回调.多线程.定时器.动画等. hello_world.html <ht ...
- InstallShield 脚本语言学习笔记
InstallShield脚本语言是类似C语言,利用InstallShield的向导或模板都可以生成基本的脚本程序框架,可以在此基础上按自己的意愿进行修改和添加. 一.基本语法规则 ...
随机推荐
- 百度前端技术学院(IFE)2016春季学期总结
今天(5月16日)作为第八个提交者提交了任务五十:RIA微型问卷管理平台 这样一个综合性的大任务,宣告我的IFE春季学期课程学习顺利完成.其实任务五十并不复杂,现在再让我来做,可能一周不到就写出来了, ...
- 使用switch case语句来显示月份的对应天数
方法一:控制台输入月份 package com.liaojianya.chapter1; import java.util.Scanner; /** * This program demonstrat ...
- DFS的基础训练清单
HDU 1010 (AC) HDU 1015 (AC) HDU 1016 (AC) HDU 1172 (AC) HDU 1312 (AC) POJ 2362 (AC,1011 ...
- v880 debug
zte v880手机,ubuntu中配置真机调试, 1.开启手机调试模式2.增加/etc/udev/rules.d/51-android.rules. 内容如下:SUBSYSTEM=="us ...
- Install-Package 那点事儿
为了练习使用SignaR,新建了一个.net 4.0的MVC4项目, 第一步,不用说就是先将SignaR安装到项目中,考虑到SignaR 目前已经更新到2.0 并且无法在 4.0框架下面使用,此时通过 ...
- C# 禁止 Webbrowser 控件的弹出脚本错误对话框
当IE浏览器遇到脚本错误时浏览器,左下 角会出现一个黄色图标,点击可以查看脚本错误的详细信息,并不会有弹出的错误信息框.当我们使用 WebBrowser控件时有错误信息框弹出,这样程序显的很不友好,而 ...
- thinkphp我掉下的一些坑
1.数据库连接,需要连接没有数据表前缀 如下,第二个参数必须为null,我之前写的是'',结果给我默认加了前缀 $User = M('User',Null,'DB_CONFIG2'); 2.AJAX获 ...
- php 获取客户端IP地址
/** * 获取真实IP地址 */ /* 在PHP中getenv(参数)函数是一个用于获取环境变量的函数,根据提供不同的参数可以获取不同的环境变量, getenv("REMOTE_ADDR& ...
- #Leet Code# Unique Tree
语言:Python 描述:使用递归实现 class Solution: # @return an integer def numTrees(self, n): : elif n == : else: ...
- iOS: 学习笔记, Swift与Objective-C混用总结
Swift与Objective-C交互总结 在Swift中使用Objective-C(简单) 在创建OjbC文件时, XCode会提示创建XXX-Bridging-Header.h文件, 创建之 在创 ...