Lua 部分语法的 BNF 在 Lex 中实现方法

.Net技术 码拜 4年前 (2016-02-23) 280次浏览
引用部分与本问题无关

引用

sp1234回了句“适合在家做简单的小偷程序来”猎奇“,本人就很郁闷,本人偷啥了,于是乎整天没精打采的,而且有点小情绪,这会一看,”偷“字明显是多打出来的Lua 部分语法的 BNF 在 Lex 中实现方法

引用

在 怎么做脚本代码编辑器 那个帖子感觉说不太清楚本人现在遇到的问题,于是重新提个问。
根据 wanghui0380 给的提示(BNF, Yacc),本人整个看过了,然后也大致理解了 Lex和Yacc 的功能原理。两者的组合是一种状态有限自动机,通过一些正则表达式来匹配全部输入,没匹配到的就不处理。但后来感觉很不方便,原因是本人开发环境是C#,它那个最后生成一个非托管程序,所以本人就计划用C#照猫画虎实现一个。

Lua 的 BNF 定义本人是在 Lua 官网上找到的:The Complete Syntax of Lua
其中一些结构简单点的类型定义还好,都写出对应的正则表达式了,例如:

	funcname ::= Name {`.´ Name} [`:´ Name]
	namelist ::= Name {`,´ Name}

但是碰上有“循环引用”的部分,本人就懵了,到底该咋写。这问题其实在一个月以前就困扰着本人。例如:

	prefixexp ::= var | functioncall | `(´ exp `)´
	functioncall ::=  prefixexp args | prefixexp `:´ Name args 

prefixexp 里面有 functioncall, 而 functioncall 里面又有 prefixexp。
结果还是得把一大堆代码贴出来。
首先本人定义了一种格式来存储这些 BNF Token:
Lua 部分语法的 BNF 在 Lex 中实现方法
然后用一个方法来将包含其他 Token 定义的 Token 变为最原始的正则表达式字符串:

    public class RegexBuilder
    {
        private static Dictionary<string, string> tokenMap = new Dictionary<string, string>();
        private static Regex tokenReg = new Regex(@"\{[a-zA-Z]+?\}");
        public static void Build(BNF bnfData)
        {
            try
            {
                foreach (var item in bnfData.TokenList)
                {
                    if (RegexBuilder.tokenMap.ContainsKey(item.Name))
                    {
                        DataException.Throw<Exception>("There is already an item exists with same name: {0}", item.Name);
                    }
                    RegexBuilder.tokenMap.Add(string.Format("{{{0}}}", item.Name), item.Value);
                }
                foreach (var item in bnfData.TokenList)
                {
                    RegexBuilder.UpdateToken(item);
                }
                bnfData.TokenList.ForEach(item => item.BuildRegex());
                tokenMap.Clear();
            }
            catch
            {
                throw;
            }
        }
        private static void UpdateToken(Token token)
        {
            StringBuilder newToken = new StringBuilder();
            MatchCollection matches = tokenReg.Matches(token.Value);
            if (matches.Count > 0)
            {
                int lastMatchPos = 0;
                foreach (Match match in matches)
                {
                    string regexStr = match.Groups[0].Value;
                    newToken.Append(token.Value.Substring(lastMatchPos, match.Groups[0].Index - lastMatchPos));
                    lastMatchPos = match.Groups[0].Index + match.Groups[0].Length;
                    if (RegexBuilder.tokenMap.ContainsKey(regexStr))
                    {
                        newToken.Append(tokenMap[regexStr]);
                    }
                    else
                    {
                        DataException.Throw<Exception>("There is no token exists with name: {0}", token);
                    }
                }
                newToken.Append(token.Value.Substring(lastMatchPos));
                token.Value = newToken.ToString();
                RegexBuilder.UpdateToken(token);
            }
        }
    }

很显然碰上有“循环引用”的部分就无限递归了。
所以本人想知道这种问题该怎么解决。
不知道说清楚了没,上次提的问题很失败所以直接结贴了Lua 部分语法的 BNF 在 Lex 中实现方法

解决方案

30

Lua,不会

35

直接看llex.c不就行了
都是一个个字符读进来,再根据状态进行分析的
反正顶层的元素是chunk,只要他不被嵌套就行了
至于后面的元素,原因是是按顺序来的,不管prefixexp 还是functioncall 总有先来后到

35

引用 3 楼 shaoerbao 的回复:
Quote: 引用 2 楼 shingoscar 的回复:

直接看llex.c不就行了
至于后面的元素,原因是是按顺序来的,不管prefixexp 还是functioncall 总有先来后到

那两个c文件实在看不下去,虽然注释很多,但还是不习惯。
就按你的思路试试看吧。其实本人问的就是嵌套的情况

也可以看c#的实现,nlua,moon之类的


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明Lua 部分语法的 BNF 在 Lex 中实现方法
喜欢 (0)
[1034331897@qq.com]
分享 (0)