如何构建真值表生成器?

时间:2009-07-05 21:40:44

标签: c# parsing boolean-logic parser-generator truthtable

我正在寻求将真值表生成器编写为个人项目。

有几个基于网络的在线版herehere

alt text
(Example screenshot of an existing Truth Table Generator

我有以下问题:

  • 我应该如何解析表达式,如:((P => Q)&(Q => R))=> (P => R)
  • 我应该使用像ANTLr或YACC这样的解析器生成器,还是使用直接的正则表达式?
  • 一旦解析了表达式,我该如何生成真值表?表达式的每个部分都需要划分为最小的组件,并从表的左侧重新构建。我该如何评价这样的东西?

任何人都可以向我提供有关解析这些任意表达式并最终评估解析表达式的提示吗?

5 个答案:

答案 0 :(得分:23)

这听起来像一个伟大的个人项目。您将学到很多关于编译器基本部分如何工作的知识。我会跳过尝试使用解析器生成器;如果这是为了您自己的启发,您将从头开始学习更多知识。

这种系统的运作方式是我们理解自然语言的形式化。如果我给你一句话:“狗,罗孚,吃他的食物。”,你要做的第一件事就是把它分解成文字和标点符号。 “The”,“SPACE”,“dog”,“COMMA”,“SPACE”,“Rover”,......这就是“象征化”或“lexing”。

接下来要做的就是分析令牌流以查看句子是否具有语法性。英语语法极其复杂,但这句话非常简单。主题同位语谓宾。这是“解析”。

一旦你知道这句话是语法的,你就可以分析这句话,从而真正从中得到意义。例如,你可以看到这句话有三个部分 - 主语,同位语和对象中的“他” - 所有这些都指的是同一个实体,即狗。你可以弄清楚狗是吃东西的东西,食物就是被吃掉的东西。这是语义分析阶段。

编译器然后有第四阶段,人类没有,这是他们生成代表语言中描述的动作的代码。

所以,做那一切。首先定义语言的标记是什么,为每个标记定义基类标记和一堆派生类。 (IdentifierToken,OrToken,AndToken,ImpliesToken,RightParenToken ......)。然后编写一个接受字符串并返回IEnumerable'的方法。那是你的词法分析员。

其次,弄清楚你的语言的语法是什么,并编写一个递归下降解析器,将IEnumerable分解为一个抽象语法树,代表你语言中的语法实体。

然后编写一个分析器,查看该树并找出数据,例如“我有多少个不同的自由变量?”

然后编写一个代码生成器,它会发出评估真值表所需的代码。吐痰IL似乎有点矫枉过正,但如果你想成为真正的buff,你可以。让表达式树库为您做这件事可能更容易;您可以将解析树转换为表达式树,然后将表达式树转换为委托,并评估委托。

祝你好运!

答案 1 :(得分:2)

我认为解析器生成器是一种矫枉过正。您可以使用将表达式转换为postfix和evaluating postfix expressions(或直接从中缀表达式构建表达式树并使用它来生成真值表)来解决此问题的想法。

答案 2 :(得分:1)

正如Mehrdad所提到的,你应该能够在学习词法分析器/解析器的语法的同时手动解析。你想要的最终结果是你给出的表达式的一些抽象语法树(AST)。

然后,您需要构建一些输入生成器,为表达式中定义的符号创建输入组合。

然后迭代输入集,根据您在第一步中解析的规则(AST)生成每个输入组合的结果。

我该怎么做:

我可以想象在解析树时使用lambda函数表达AST /规则,并在解析时构建符号表,然后可以构建输入集,将符号表解析为lambda表达式树,以进行计算结果。

答案 3 :(得分:1)

如果您的目标是处理布尔表达式,那么解析器生成器和所有使用的机器都是浪费时间,除非您想要了解它们是如何工作的(然后它们中的任何一个都没问题。)

但是为布尔表达式手动构建递归下降解析器很容易,它计算并返回“计算”表达式的结果。可以在第一遍使用这样的解析器来确定唯一变量的数量,其中“评估”意味着“为每个新变量名称分配1”。 编写生成器以生成N个变量的所有可能的真值是微不足道的;对于每组值,只需再次调用解析器并使用它来计算表达式,其中evaluate表示“根据运算符组合子表达式的值”。

你需要一个语法:

formula = disjunction ;
disjunction = conjunction 
              | disjunction "or" conjunction ;
conjunction = term 
              | conjunction "and" term ;
term = variable 
       | "not" term 
       |  "(" formula ")" ;

你的可能会更复杂,但对于布尔表达式,它不会那么复杂。

对于每个语法规则,将1个子例程写入正在解析的字符串中使用全局“scan”索引:

  int disjunction()
 // returns "-1"==> "not a disjunction"
 // in mode 1:
 // returns "0" if disjunction is false
 // return  "1" if disjunction is true
 { skipblanks(); // advance scan past blanks (duh)
   temp1=conjunction();
   if (temp1==-1) return -1; // syntax error
   while (true)
     { skipblanks();
       if (matchinput("or")==false) return temp1;
       temp2= conjunction();
       if (temp2==-1) return temp1;
       temp1=temp1 or temp2;
     }
  end

  int term()
  { skipblanks();
    if (inputmatchesvariablename())
       { variablename = getvariablenamefrominput();
         if unique(variablename) then += numberofvariables;
         return lookupvariablename(variablename); // get truthtable value for name
       }
     ...
  }

你的每一个解析程序都是关于这个复杂的。严重。

答案 4 :(得分:0)

您可以在http://code.google.com/p/pyttgen/source/browse/#hg/src获取pyttgen程序的源代码。它为逻辑表达式生成真值表。代码基于ply库,所以很简单:)