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

runerback 2016-06-29 05:57:14
引用部分与本问题无关

引用
sp1234回了句“适合在家做简单的小偷程序来”猎奇“,我就很郁闷,我偷啥了,于是乎整天没精打采的,而且有点小情绪,这会一看,”偷“字明显是多打出来的


引用
在 怎么做脚本代码编辑器 那个帖子感觉说不太清楚我现在遇到的问题,于是重新提个问。
根据 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:

然后用一个方法来将包含其他 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);
}
}
}

很显然碰上有“循环引用”的部分就无限递归了。

所以我想知道这种问题该怎么解决。

不知道说清楚了没,上次提的问题很失败所以直接结贴了
...全文
220 5 打赏 收藏 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
runerback 2016-07-05
  • 打赏
  • 举报
回复
找了好几个,结果都看的一头雾水,包括notepad++和scite。 我还是先绕过交叉引用的那些,先搞最基础的正则表达式吧。结帖结贴
Poopaye 2016-06-30
  • 打赏
  • 举报
回复
引用 3 楼 shaoerbao 的回复:
[quote=引用 2 楼 shingoscar 的回复:] 直接看llex.c不就行了 至于后面的元素,因为是按顺序来的,不管prefixexp 还是functioncall 总有先来后到
那两个c文件实在看不下去,虽然注释很多,但还是不习惯。 就按你的思路试试看吧。其实我问的就是嵌套的情况[/quote] 也可以看c#的实现,nlua,moon之类的
runerback 2016-06-30
  • 打赏
  • 举报
回复
引用 2 楼 shingoscar 的回复:
直接看llex.c不就行了 至于后面的元素,因为是按顺序来的,不管prefixexp 还是functioncall 总有先来后到
那两个c文件实在看不下去,虽然注释很多,但还是不习惯。 就按你的思路试试看吧。其实我问的就是嵌套的情况
Poopaye 2016-06-29
  • 打赏
  • 举报
回复
直接看llex.c不就行了 都是一个个字符读进来,再根据状态进行分析的 反正顶层的元素是chunk,只要他不被嵌套就行了 至于后面的元素,因为是按顺序来的,不管prefixexp 还是functioncall 总有先来后到
圣殿骑士18 2016-06-29
  • 打赏
  • 举报
回复
Lua,不会

111,128

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧