实现自己的脚本语言ngscript之一:词法分析

正则表达式的理论基础可以参考装配脑袋

如果学过编译原理的课程就更好了。

 

词法分析用到了我写的一个工具lexeroid。

下面说一些我写lexeroid时候遇到的问题。

Unicode

装配脑袋 的 自己动手开发编译器(四)利用DFA转换表建立扫描器 中,提到了等价类处理Unicode的方法。

我做了一些改进。

首先我把DFA Edge的输入改了,不再是一个char这种,而是一个Input类,它接受空(epsilon)或者begin和end范围(左闭右开区间)内的char。

然后我就可以把char1写成这样

    public static NFA char1() {
        return Re.range(0, 131072);
    }

然后就支持中文了……

而定义regex时冲突的部分,比如定义了一个'a'-'z'的Input和一个'g'的Input在同一个Vertex上,会有一个reduce函数把'a'-'z'分离成'a'-'f'和'h'-'z'。

 

最长匹配

这个很多书上应该介绍过,就是设置一个lastFinal一样的东西,然后在DFA停机的时候把最后一个正确匹配的取出来。

 

NFA的组织

最开始我做的是把每个token的NFA分开,存成一个数组,然后每个生成DFA之后,在词法分析的时候一个一个去测试。后来发现这个似乎和用Java内置的正则表达式没什么区别。而且有一个问题是,token定义的顺序要十分小心,因为先定义的token会被优先匹配到。

后来我试了另外一种方法,就是等所有token生成NFA完之后,添加一个入口,用epsilon边把所有的NFA连起来形成一个大NFA,然后再用它生成的DFA去匹配。

 

最后

lexeroid定义token时大概是这个样子

        LexerBuilder builder = new LexerBuilder();
        builder.defineToken("if", Re.string("if"));
        builder.defineToken("return", Re.string("return"));
        builder.defineToken("else", Re.string("else"));
        builder.defineToken("ident", Re.concat(
                Re.or(Re.letter(), Re.chr('_')),
                Re.many(Re.or(Re.or(Re.letter(), Re.chr('_')), Re.digit()))
        ));
        builder.defineToken("string",
                Re.concat(Re.chr('"'), Re.many(Re.char1()), Re.chr('"'))
        );

     //此处省略N行
     return builder.build();

 

代码可以从这里找到

https://github.com/wssccc/lexeroid.git

作为一个词法分析器,后面的文章中还会用到它。

 

相关资料

转载于:https://www.cnblogs.com/wssccc/p/3580123.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值