我正在学习使用Alex和Happy编写一个小编译器.我想维护AST节点的行和列信息,以便我可以向用户提供有意义的错误消息.为了说明我打算如何做,我写了一个小例子(见下面的代码),我想知道我是否接近问题的方式(将AlexPosn附加到标记,将多态属性字段附加到AST节点,使用tkPos和astAttr)是好的风格或者是否有更好的方法来处理位置信息.
Lexer.x:
{
module Lexer where
}
%wrapper "posn"
$white = [\ \t\n]
tokens :-
$white+ ;
[xX] { \pos s -> MkToken pos X }
"+" { \pos s -> MkToken pos Plus }
"*" { \pos s -> MkToken pos Times }
"(" { \pos s -> MkToken pos LParen }
")" { \pos s -> MkToken pos RParen }
{
data Token = MkToken AlexPosn TokenClass
deriving (Show, Eq)
data TokenClass = X
| Plus
| Times …Run Code Online (Sandbox Code Playgroud) 我正在为我正在学习的课程编写一个编译器.该类不是专门的Haskell,而是我使用Haskell编写我的编译器和解释器.我有一个cabal包设置,希望我的教授可以轻松运行/编译.我对构建工具字段中的两个可执行文件感到高兴和alex,但是Cabal忽略了这一点,然后抱怨它无法找到Happy和Alex应该生成的模块.如果我手动运行:
alex LimpScanner.x
happy LimpParser.y
Run Code Online (Sandbox Code Playgroud)
然后cabal完美运行.
我以为我让cabal自动运行它们,但也许我记得不完美.
limp.cabal:
-- limp.cabal auto-generated by cabal init. For additional options,
-- see
-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
-- The name of the package.
Name: limp
-- The package version. See the Haskell package versioning policy
-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
-- standards guiding when and how versions should be incremented.
Version: 0.1
-- A short (one-line) description of the package.
Synopsis: LIMP Compiler (Compiler Construction course project)
-- A longer description of the package.
-- Description:
-- URL …Run Code Online (Sandbox Code Playgroud) 我正在开展一个学校项目,我必须使用Alex + Happy在Haskell中为一种简单的语言构建一个解释器.
仔细阅读文档后我了解了大部分内容,但希望看到使用这些工具的完整示例.
在一个阶段中混合词法分析器和解析阶段有时会使Parsec解析器的可读性降低,但也会降低它们的速度.一种解决方案是使用Alex作为标记化器,然后使用Parsec作为标记流的解析器.
这很好但是如果我能摆脱Alex会更好,因为它在编译管道中添加了一个预处理阶段,与haskell"IDE"等没有很好地集成.我想知道是否有这样的事情用于描述标记器的haskell EDSL,非常符合Alex的风格,但是作为库.
我正在尝试学习使用Alex + Happy来构建解析器,特别是我有兴趣学习使用monadAlex 的包装器.我已经看过亚历克斯和快乐的文档,但对于我来说,他们都非常缺乏将它们一起使用的任何有用信息.我设法让它们basic和posn包装纸一起工作,但我很茫然monad.
我已经看过关于Alex,Happy和monadic词法分析器的不同问题(包括:是否有关于使用Alex + Happy构建简单解释器的任何教程?但没有一个能够提供一个使用的简单示例monad.
大多数在线代码使用Happy与自定义词法分析器函数,或使用basic或posnAlex包装器.
这是一个类似ini的语法的简单词法分析器:
{
module IniLexer where
}
%wrapper "monad"
$spaces = [\ \t]
$alpha = [a-zA-Z]
$digits = [0-9]
$alnum = [$alpha$digits]
@identifier = $alpha $alnum*
@comment = \#.*
@integer = $digits+
@boolean = (true) | (false)
@string = \"[^\"]*\"
:-
@integer { mkL LInteger }
@boolean { mkL LBoolean }
@string { …Run Code Online (Sandbox Code Playgroud) 源树happy中包含AttrGrammarParser.ly与Parser.ly和源树alex包含Scan.x.然而,据我所知,为了编译happy,我们需要使用... 将.ly文件转换为.lhs文件happy,并且为了编译,alex我们需要使用... 将.x文件转换为.hs文件alex.
因此,为了编译任一工具,似乎必须进行一些自举.
Setup.lhs每个项目的文件都包含一些模板扩展,但据我所知,不要做任何特别的事情来进行自举.
引导如何以及在哪里完成?
在使用Alex lexer生成器或Happy解析器生成器创建一个Lexer.x或一个Parser.y解析器时,将它们编译成Haskell文件,并将它们编译成目标文件,默认情况下会产生以下"警告":
$ ghc Lexer
line-map.c: file "<command-line>" left but not entered
line-map.c: file "<command-line>" left but not entered
[1 of 1] Compiling Lexer ( Lexer.hs, Lexer.o )
$ happy Parser.y
$ ghc Parser
line-map.c: file "<command-line>" left but not entered
line-map.c: file "<command-line>" left but not entered
[2 of 2] Compiling Parser ( Parser.hs, Parser.o )
Run Code Online (Sandbox Code Playgroud)
这些行是由于生成的.hs文件中嵌入了以下行而产生的:
{-# LINE 1 "<command-line>" #-}
Run Code Online (Sandbox Code Playgroud)
为什么包含这些行,并且有一种方法可以抑制这些消息,以防命令行显然没有用于生成的词法分析器和解析器中的任何内容?
我正在研究一个小的Haskell项目,该项目需要能够将一小部分严格形成的英语用于令牌以进行语义分析.对于具有许多不同末端效应器的系统而言,它是一种非常天真的自然语言接口,而不是可以发出的命令.我目前正在使用Alex,但Alex依赖其词典进行静态编译.系统的性质使得世界上的末端效应器的数量甚至类型可以在编译之后增加和减少,因此我需要能够在运行时从词典中添加或移除可行的令牌.
我已经尝试过寻找动态lexing解决方案,而我最接近的是这款动态Lexer引擎,自2000年以来看起来并没有更新.
我一直在考虑一些技术,比如使用较低级别的方法(也许是Attoparsec),甚至为Alex配置重新编译钩子并将词法分析器与应用程序的其余部分分开.
这种词汇分析有哪些众所周知的解决方案?我打算最终通过自然语言处理为工作程序员工作,所以我可以采用一种不那么简化的方法,但目前基本的词法分析器是我需要的.
我正在使用 Alex + Happy 为 Haskell 中的 DSL 制作解析器。我的 DSL 使用掷骰子作为可能表达式的一部分。
有时我有一个我想解析的表达式,如下所示:
[some code...] 3D6 [... rest of the code]
Run Code Online (Sandbox Code Playgroud)
这应该大致翻译为:
TokenInt {... value = 3}, TokenD, TokenInt {... value = 6}
Run Code Online (Sandbox Code Playgroud)
我的 DSL 也使用变量(基本上是字符串),所以我有一个特殊的标记来处理变量名。所以,有了这个令牌:
"D" { \pos str -> TokenD pos }
$alpha [$alpha $digit \_ \']* { \pos str -> TokenName pos str}
$digit+ { \pos str -> TokenInt pos (read str) }
Run Code Online (Sandbox Code Playgroud)
我现在使用解析时得到的结果是:
TokenInt {... value = 3}, TokenName { ... , name …Run Code Online (Sandbox Code Playgroud) 我试图理解亚历克斯和词法分析者的一般情况,但是我很难运行我的词法分析器.
我用"基本"和"posn"包装器写了词法分析器,但我不能用"monad"包装器.我想我必须使用monad包装器,因为我需要在输入中收集字符串和标记位置.我还需要多个州.现在我正试图运行这个简单的例子:
{
module Main (main) where
}
%wrapper "monad"
$whitespace = [\ \b\t\n\f\v\r]
$digit = 0-9
$alpha = [a-zA-Z_]
$upper = [A-Z]
$lower = [a-z]
@tidentifier = $upper($alpha|_|$digit)*
@identifier = $lower($alpha|_|$digit)*
tokens :-
$whitespace+ ;
$upper $alpha+ { typeId }
$lower $alpha+ { id_ }
$digit+ { int }
{
data Lexeme = L AlexPosn LexemeClass String
data LexemeClass
= TypeId String
| Id String
| Int Int
| EOF
deriving (Show, Eq)
typeId :: AlexInput -> …Run Code Online (Sandbox Code Playgroud)