我需要解析一个我没有设计的简单专有语言,因此我无法改变语言。我需要C#中的结果,所以我一直在使用TinyPG因为它易于使用,并且不需要外部库来运行解析器。 TinyPG生成一个简单的LL(1)解析器。
我目前遇到的问题与语言如何将文件分成几个部分有关。它有不同类型变量的部分,设置它们的初始值,方程定义等。我只关心声明变量的部分,所以我想忽略其余部分。我不了解其他部分的所有规则,也不想弄明白。它们可能被视为评论。
这是一个代码示例:
PARAMETER
Density AS REAL
CrossSectionalArea AS REAL
SET # Parameter values
T101.FO := "SimpleEventFOI::dummy";
T101.CrossSectionalArea := 1 ; # m2
EQUATION
OutSingleInt = SingleInt;
OutArrayInt = ArrayInt;
我关心PARAMETER和SET部分,但不关心EQUATION部分。如您所见,问题是这些部分没有END标记。因此,当我得到不同的关键字时,我无法弄清楚如何告诉语法某个部分结束,但新关键字可能会开始一个新的部分。在我的尝试中,新的部分起始关键字被消耗以关闭旧部分。
这里列出的部分比我在这里列出的要多得多,其中一部分是我关心的,有些部分我不是。它们似乎分为两种类型,"看起来像PARAMETER"在陈述结尾处没有分号,"看起来像EQUATION"哪个。这种语言不是大小写或空白敏感的。这些部分可以是任何顺序。 (例如SET,EQUATION,PARAMETER)除了评论之外,整个事情可以写在一行上。
目前我通过使用正则表达式来查找我感兴趣的部分,并且仅将这些部分提供给解析器,但我也遇到了麻烦。正则表达式,适用于所有情况,但不会意外地在评论中选取关键字。我可能最终只是扩展这个解决方案来解决它的问题,但直接在语法中解决问题会更好。这可能不仅仅是LL(1)语言。
答案 0 :(得分:0)
我尝试了以下tpg代码,它可以解析你的例子。看起来TinyPG无法区分关键字和id,所以我稍微破解了ID。
//Tiny Parser Generator v1.3
//Copyright © Herre Kuijpers 2008-2012
<% @TinyPG Namespace="Test" %>
PARAMETER -> @"PARAMETER";
SET -> @"SET";
EQUATION -> @"EQUATION";
AS -> @"AS";
ID -> @"\b(?!(PARAMETER|SET|EQUATION)\b)([a-zA-Z]\w+)";
DOT -> @"\.";
EQ -> @":=";
EXPR -> @"\d|""[^""]*""";
END -> @";";
[Skip] WS -> @"\s+|#[^\r\n]+";
EQDECL -> @"\b(?!(PARAMETER|SET|EQUATION)\b)([^#;]+)";
Equations -> EQUATION (EQDECL END)*;
Parameters -> PARAMETER ParamDecl*;
ParamDecl -> ID AS ID;
Sets -> SET SetDecl*;
SetDecl -> FullId EQ EXPR END;
FullId -> ID DOT ID;
Section -> Equations | Parameters | Sets;
Start -> Section*;