我正在尝试为下面的命令定义语法.
object ParserWorkshop {
def main(args: Array[String]) = {
ChoiceParser("todo link todo to database")
ChoiceParser("todo link todo to database deadline: next tuesday context: app.model")
}
}
Run Code Online (Sandbox Code Playgroud)
第二个命令应该标记为:
action = todo
message = link todo to database
properties = [deadline: next tuesday, context: app.model]
Run Code Online (Sandbox Code Playgroud)
当我在下面定义的语法上运行此输入时,我收到以下错误消息:
[1.27] parsed: Command(todo,link todo to database,List())
[1.36] failure: string matching regex `\z' expected but `:' found
todo link todo to database deadline: next tuesday context: app.model
^
Run Code Online (Sandbox Code Playgroud)
据我所知,它失败了,因为匹配消息的单词的模式几乎与属性键的键的模式相同:值对,因此解析器无法分辨消息的结束位置和属性的开始.我可以通过坚持为每个属性使用开始令牌来解决这个问题,如下所示:
todo link todo to database :deadline: next tuesday …Run Code Online (Sandbox Code Playgroud) 我目前正在寻找一个词法分析器/解析器,它从BNF语法(ocamlyacc具有优先级和关联性的文件)生成Scala代码.我很困惑,因为我几乎没有发现如何做到这一点.
对于解析,我发现scala-bison(我有很多麻烦可以使用).所有其他工具都只是导入Scala的Java解析器(如ANTLR).
对于乐兴来说,我一无所获.
我还找到了Scala 的着名解析器组合器,但是(如果我错了,请纠正我),即使它们非常吸引人,它们也会消耗大量的时间和内存,这主要是由于回溯.
所以我有两个主要问题:
什么是使我的解析器尊重(忽略)C风格注释的最简单方法.我对两种评论类型都感兴趣,但也欢迎只有一种类型的解决方案.
我目前只是在扩展JavaTokenParsers.
我想知道Scalas/Haskells解析器组合器是否足以解析编程语言.更具体地说,语言MiniJava.我正在阅读compiller构建和jflex和java杯是非常痛苦的工作所以我想知道我是否可以/应该使用解析器组合器.MiniJava语法非常小.MiniJavas BNF:http://www.cambridge.org/us/features/052182060X/grammar.html
compiler-construction parsing haskell scala parser-combinators
最近我一直在为算术表达式寻找一个合适的语法,但发现只有微不足道的语法pow(..., ...),例如忽略了.然后我自己尝试了,但有时它没有按照预期工作.例如,我错过了-在表达式前允许一元并修复它.也许有人可以看看我目前的方法并改进它.此外,我认为其他人可以利用,因为能够解析算术表达式是一项常见任务.
import scala.math._
import scala.util.parsing.combinator._
import scala.util.Random
class FormulaParser(val constants: Map[String,Double] = Map(), val userFcts: Map[String,String => Double] = Map(), random: Random = new Random) extends JavaTokenParsers {
require(constants.keySet.intersect(userFcts.keySet).isEmpty)
private val allConstants = constants ++ Map("E" -> E, "PI" -> Pi, "Pi" -> Pi) // shouldn´t be empty
private val unaryOps: Map[String,Double => Double] = Map(
"sqrt" -> (sqrt(_)), "abs" -> (abs(_)), "floor" -> (floor(_)), "ceil" -> (ceil(_)), "ln" -> (math.log(_)), "round" -> (round(_)), "signum" …Run Code Online (Sandbox Code Playgroud) 考虑这部分语法:
def expression = SimpleExpression ~ opt(relation ~ SimpleExpression)
def relation = "=" | "#" | "<=" | "<" | ">=" | ">" | "IN" | "IS"
def SimpleExpression = opt("+" | "-") ~ rep1sep (term, AddOperator)
def AddOperator = "+" | "-" | "OR"
def term = factor ~ rep(MulOperator ~ factor)
def MulOperator = "*" | "/" | "DIV" | "MOD" | "&"
def factor: Parser[Any] = number | "(" ~ expression ~ ")" | "~" ~ factor …Run Code Online (Sandbox Code Playgroud) parsing scala operators operator-precedence parser-combinators
我正在解析一个小的声明性语言,在一个范围内你可以声明变量(带有一个类型),然后再使用,就像在大多数其他语言中一样,使用名称(没有类型).
变量的声明如下所示:
?varname
?varname1 ?varname2 - type1
?varname3 ?varname4 ?varname5 - type2
Run Code Online (Sandbox Code Playgroud)
如果省略类型,则默认类型应该object与第一种情况类似.所以为此,我有一个特定的解析器,它返回一个我自己的域对象列表LiftedTerm(你可以假设它是一个带有变量名称和变量类型的元组,实际上它里面还有一些东西,但不相关对于这个问题):
def typed_list_variables : Parser[List[LiftedTerm]]= typed_variables.+ ^^ { case list => list.flatten.map(variable =>
LiftedTerm(variable._1, variable._2 match {
case "object" => ObjectType
case _ => TermType(variable._2)
})) }
def typed_variables = ((variable+) ~ (("-" ~> primitive_type)?)) ^^ {
case variables ~ primitive_type =>
for (variable <- variables) yield variable -> primitive_type.getOrElse("object")
}
def variable = """\?[a-zA-Z][a-zA-Z0-9_-]*""".r
def primitive_type = """[a-zA-Z][a-zA-Z0-9_-]*""".r
Run Code Online (Sandbox Code Playgroud)
这一切都很好.
现在,在相同的"范围"中,我必须解析存在对这些变量的引用的部分.该变量显然不会再次完整声明.因此,在上面的示例中,?varname1使用的位置将不包括type1 …
我想知道为什么在Haskell中没有用于自下而上解析的通用解析器组合器,就像Parsec组合器一样用于自顶向下解析.
(我可以在2004年找到一些研究工作,但在
https://haskell-functional-parsing.googlecode.com/files/Ljunglof-2002a.pdf
http://www.di.ubi.pt/~jpf/Site之后没有/Publications_files/technicalReport.pdf)
有没有具体的理由没有实现它?
对于一个小型编译器项目,我们目前正在为C的子集实现编译器,我们决定使用Haskell和megaparsec.总的来说,我们取得了很好的进展,但仍有一些我们无法正确处理的极端情况.其中之一是反斜杠的处理,然后换行.引用规范:
删除反斜杠字符()后面紧跟一个新行字符的每个实例,拼接物理源代码行以形成逻辑源代码行.只有任何物理源线上的最后反斜杠才有资格成为此类拼接的一部分.(§5.1.1.,ISO/IEC9899:201x)
到目前为止,我们提出了两种可能的方法来解决这个问题:
1.)实现一个前期阶段,其中再现初始输入并且每次出现都\\\n被删除.我们在这种方法中看到的最大缺点是我们丢失了我们需要的准确错误位置.
2.)实现一个特殊的char'组合器,其行为类似于char前方的额外角色并且将默默地消耗任何组合\\\n.这会给我们正确的立场.在此不利的是,我们需要更换每一个的occurence char与char'任何解析器,甚至在百万秒差距,提供的像string,integer,whitespace等...
我们很可能不是第一个尝试使用parsec/megaparsec来解析这种语法的人,所以我可以想象有一些更好的方法可以做到这一点.有没有人有想法?