【发布时间】:2011-01-18 16:38:38
【问题描述】:
大家好,感谢阅读
我目前正在尝试做一个谷歌风格的计算器。你输入一个字符串,它判断是否可以计算并返回结果。
我从基础开始慢慢开始:+ - / * 和括号处理。
我愿意随着时间的推移改进计算器,并且在不久前了解了一些词法分析,我建立了一个标记列表和相关的正则表达式模式。
这种工作很容易适用于 Lex 和 Yacc 等语言,除非我正在开发一个纯 Javascript 的应用程序。
我试图将这个想法转录成 Javascript,但我不知道如何以简洁美观的方式处理所有内容,尤其是嵌套括号。
分析
让我们定义什么是计算器查询:
// NON TERMINAL EXPRESSIONS //
query -> statement
query -> ε // means end of query
statement -> statement operator statement
statement -> ( statement )
statement -> prefix statement
statement -> number
number -> integer
number -> float
// TERMINAL EXPRESSIONS //
operator -> [+*/%^-]
prefix -> -
integer -> [0-9]+
float -> [0-9]+[.,][0-9]+
Javascript
词法分析包括验证没有任何东西看起来不像终端表达式之一:运算符、前缀、整数和浮点数。可以简化为一个正则表达式:
(我添加了空格以使其更具可读性)
var calcPat =
/^ (\s*
( ([+/*%^-]) | ([0-9]+) | ([0-9]+[.,][0-9]+) | (\() | (\)) )
)+ \s* $/;
如果此测试通过,则查询在词法上是正确的,需要进行语法检查以确定是否可以计算。 这是棘手的部分
我不会粘贴代码,因为它不干净也不容易理解,但我将解释我遵循的过程以及为什么我被卡住了:
我创建了一个名为isStatement(string) 的方法,它应该递归地调用自身。主要思想是将字符串拆分为“潜在”语句,并检查它们是否真的是语句并完全形成一个。
流程如下:
-如果前两个标记是数字后跟一个运算符:
-那么,
-- 如果剩下的只是一个token并且是一个数字:
--- 那么这是一个声明。
--- 否则,检查剩余标记是否形成语句(递归调用)
-否则,如果第一个标记是括号
-然后,找到匹配的右括号并检查里面是否是一个语句(递归)
-- 还要检查右括号后是否有东西,与括号结构关联时是否形成语句。
有什么问题?
我的问题是当有嵌套结构时我找不到匹配的括号。 我该怎么做? 另外,正如您所见,这不是一个特别通用和干净的语法检查算法。你有什么想法来改进这种模式吗?
非常感谢您花时间阅读所有内容。 盖尔
(PS:你可能注意到了,我不是以英语为母语的人!对错误和所有抱歉!)
【问题讨论】:
-
你可能想试试这个工具:pegjs.majda.cz/online
-
这很酷,但是(从它的名字来看)它产生了 PEG 解析器(我猜是 Packrat 解析器),这确实是一个完整的东西。经典的“词法分析器 + 解析器”方法是为上下文无关语法(或几乎与上下文无关)构建 LL 或 LR 解析器,而 PEG 描述的语言类别与 CFG 不同。
-
哦,特别值得注意的是,使用 PEG 语言的 Packrat 解析器,您根本不需要词法分析器 :-)
-
@bart-kiers:很棒的工具,谢谢。几年前我尝试自己构建一个解析器并放弃了(谢天谢地,这只是一种爱好,而不是任何工作要求)。也许我得把那个项目从架子上撤下来。
-
@bart-kiers:感谢您的链接,我设法用它构建了一个有效的解析器,但由于我不知道它是如何工作的以及其他合法的东西,我不能只是开始就这样靠他们赚钱!
标签: javascript regex pattern-matching lexical-analysis