【问题标题】:How to implement Lexical Analysis in Javascript如何在 Javascript 中实现词法分析
【发布时间】: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


【解决方案1】:

您对什么是词法分析有了正确的认识,但您似乎对标记语法语言语法之间的区别感到困惑。这是两个不同的东西。

  • token 语法 是一组模式(通常是正则表达式),用于描述要解析的语言的标记。正则表达式是基于字符集的表达式。

  • 语言语法(或 target 语法,我想)是您要解析的语言的语法。这种语法用记号表示。

你不能编写正则表达式来解析代数符号。你不能。你可以为它写一个语法,但它不是一个正则语法。您想要做的是识别单独的标记,在您的情况下,可以使用正则表达式来完成,有点像您所拥有的。诀窍是您并没有真正将该表达式应用于要解析的整个句子。相反,您想在句子的当前点匹配一个标记。

现在,因为您可以使用 Javascript 正则表达式,您可以想出一个正则表达式来匹配一串标记。诀窍是想出一种方法来识别哪个令牌与可能性列表匹配。 Javascript 正则表达式引擎可以为您返回组数组,所以也许您可以在此基础上构建一些东西。

edit — 我正在尝试从一个单独的正则表达式列表(每个标记一个)开始,找出如何组合一个(有点)通用的标记生成器构建器。它可能不是很复杂,而且会很有趣。

【讨论】:

  • 确实如此,否则你会陷入RegEx match open tags except XHTML self-contained tags的经典答案的陷阱。
  • @Pointy 谢谢你的时间。在思考和浏览解析器和令牌时,我偶然发现了 D. Crockford 的这篇文章,我记得很久以前读过这篇文章,但什么都不懂。现在它更有意义了。您认为值得深入研究并实际尝试构建我自己的解析器吗? javascript.crockford.com/tdop/tdop.html
  • @Marcel Korpel:感谢您的建议!这有点让我想问如何解析 XHTML 只是为了看看人们的反应:D
  • @Gaël 构建解析器很有教育意义,也很有趣;这是锻炼程序设计技能的好方法。至于那个特定的解析技术,嗯,我不太了解。我想这和其他任何事情一样值得。
  • @Pointy 我终于设法使用上面发布的链接构建了自己的解析器。想到我可以用它来解析 Javascript 本身就非常了不起,而且确实很有趣!谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-21
  • 1970-01-01
  • 2017-04-22
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
相关资源
最近更新 更多