解决语法问题的实用解决方案

时间:2011-07-08 08:37:25

标签: parsing vb6 grammar recursive-descent left-recursion

我们有很少的vb6代码片段(唯一使用的是功能的子集),这些代码片段得到了非程序员的支持。这些被称为规则。对于编写这些内容的人来说,他们很难调试,所以有人编写了一种add hoc解析器,能够评估子表达式,从而更好地显示问题所在。

这个addhoc解析器非常糟糕,并没有真正起作用。所以我试着写一个真正的解析器(因为我手工编写它(没有解析器生成器,我可以用vb6后端理解)我想用递归正确的解析器)。我不得不对语法进行反向工程,因为我能找到任何东西。 (事实上​​,我发现了一些http://www.notebar.com/GoldParserEngine.html,但它的LALR和它的方式比我需要的更大)

这是VB子集的语法。

<Rule>                 ::=  expr rule | e
<Expr>                 ::= ( expr )
                           | Not_List CompareExpr <and_or> expr
                           | Not_List CompareExpr

<and_or>                   ::= Or | And

<Not_List>             ::= Not Not_List | e

<CompareExpr>          ::= ConcatExpr comp CompareExpr
                           |ConcatExpr

<ConcatExpr>           ::= term  term_tail & ConcatExpr
                           |term term_tail

<term>                 ::= factor factor_tail
<term_tail>            ::= add_op term term_tail | e

<factor>               ::= add_op Value | Value
<factor_tail>          ::= multi_op  factor factor_tail | e

<Value>                ::= ConstExpr | function | expr

<ConstExpr>            ::= <bool> | number | string | Nothing
<bool>                 ::= True | False
<Nothing>              ::= Nothing | Null | Empty

<function>             ::= id | id ( ) | id ( arg_list )
<arg_list>             ::= expr , arg_list | expr

<add_op>               ::= + | -
<multi_op>             ::= * | /
<comp>                 ::= > | < | <= | => |  =< | >= |  = | <>

总而言之,这里有一些非常好的例子:

my_function(1, 2 , 3)  

看起来像

(Programm
 (rule
  (expr
   (Not_List)
   (CompareExpr
    (ConcatExpr
     (term
      (factor
       (value
        (function
         my_function
         (arg_list
          (expr
           (Not_List)
           (CompareExpr
            (ConcatExpr (term (factor (value 1))) (term_tail))))
          (arg_list
           (expr
            (Not_List)
            (CompareExpr
             (ConcatExpr (term (factor (value 2))) (term_tail))))
           (arg_list
            (expr
             (Not_List)
             (CompareExpr
              (ConcatExpr (term (factor (value 3))) (term_tail))))
            (arg_list))))))))
     (term_tail))))
  (rule)))

现在我的问题是什么?

如果您的代码看起来像这样(( true OR false ) AND true)我有一个无限递归但真正的问题是(true OR false) AND true(在第一个( expr )之后)只被理解为{{ 1}}。

这是Parstree: Parse Tree

那么如何解决这个问题。我应该以某种方式更改语法还是使用一些实施黑客?

如果您需要它,可能会有一些困难。

(true or false)

2 个答案:

答案 0 :(得分:1)

我看到了几个问题。

您将OR和AND视为相同的优先级运算符。 OR应该有单独的规则,对于AND。否则,对于表达式A OR B AND C,您将具有错误的优先级(因此评估)。

因此,作为第一步,我将修改您的规则如下:

<Expr>  ::= ( expr )                        
            | Not_List AndExpr Or  Expr   
            | Not_List AndExpr

<AndExpr>  ::=                        
            | CompareExpr And  AndExpr   
            | Not_List CompareExpr

下一个问题是您的(expr)位于列表的顶层。如果我写的话怎么办?

 A AND (B OR C)

要解决此问题,请更改以下两条规则:

<Expr>  ::= Not_List AndExpr Or Expr   
            | Not_List AndExpr

<Value> ::= ConstExpr | function | ( expr )

我认为你的Not的实现是不合适的。不是运营商, 只有一个操作数,所以它的“树”应该有一个Not节点和一个子节点 表达式是Notted。你有没有操作数的Nots列表。 试试这个:

<Expr>  ::= AndExpr Or Expr   
            | AndExpr

<Value> ::= ConstExpr | function | ( expr ) | Not Value

我没看过,但我认为VB6表达式中还有其他杂乱的东西。

如果你注意到,Expr和AndExpr的样式我已经编写了使用 right 递归来避免 left 递归。您应该更改Concat,Sum和Factor规则以遵循类似的风格;你所拥有的是非常复杂和难以理解的。

答案 1 :(得分:0)

如果他们只是创建片段,那么也许VB5“足够好”来创建它们。如果VB5足够好,免费的VB5 Control Creation Edition可能值得追踪,以供他们使用:

http://www.thevbzone.com/vbcce.htm

你可以让他们从他们添加片段的“测试工具”项目开始,他们甚至可以测试它们。

通过一个小方向,这可能比手工制作语法分析器更实用,而且更有用,因为它们可以测试的不仅仅是正确的语法。

缺少VB5时,你可能在“测试工具”中包含一个静态模块,它提供了一个粗略的,准备好的Split(),Replace()等等:

http://support.microsoft.com/kb/188007