Parsing 使用ocamlyacc减少/减少冲突

Parsing 使用ocamlyacc减少/减少冲突,parsing,ocaml,ocamlyacc,Parsing,Ocaml,Ocamlyacc,我正在努力学习一种语法,它涉及类型表达式以及变量访问。解析期间无法确定此访问的结果类型,将在第二步中对其进行评估。这个计算不是问题,但似乎很难编写明确的解析器规则 在不同类型上工作的所有操作(例如比较运算符)都会产生reduce/reduce冲突。很明显,这是因为解析器无法决定是将“x.a=y.b”解析为“bool\u expr EUQAL bool\u expr”还是“num\u expr EUQAL num\u expr”,因为类型不确定。但是,comp_op规则的结果类型是确定的(因为它总

我正在努力学习一种语法,它涉及类型表达式以及变量访问。解析期间无法确定此访问的结果类型,将在第二步中对其进行评估。这个计算不是问题,但似乎很难编写明确的解析器规则

在不同类型上工作的所有操作(例如比较运算符)都会产生
reduce/reduce
冲突。很明显,这是因为解析器无法决定是将“
x.a=y.b
”解析为“
bool\u expr EUQAL bool\u expr
”还是“
num\u expr EUQAL num\u expr
”,因为类型不确定。但是,
comp_op
规则的结果类型是确定的(因为它总是一个布尔值)

有没有解决这个问题的方法,而不必在解析过程中丢弃所有类型信息,并且总是在求值阶段进行检查

下面是一个简短的语法示例(使用ocamlex和ocamlyacc):


谢谢您的帮助。

正如ygrek所说,您不应该尝试将解析和键入混为一谈。只使用表达式的一个语法类别编写解析器要容易得多,然后使用一个单独的类型检查过程来解决这个问题

从理论上讲,这源于这样一个事实:键入规则所做的区分比传统解析技术所能表达的要精细得多。他们一直试图使用属性语法等更声明性地指定类型规则,但您通常使用的LL/LR技术肯定不适合,这就像用正则表达式解析嵌套括号一样


最后,您应该使用而不是ocamlyacc,因为它更好。您将拥有更具可读性和表达性的语法(命名参数、参数化规则…),更好的错误报告和语法调试功能。

正如前面所说,您将很难编写“类型正确的解析器”——根据您的语言,这甚至可能是不可能的

无论如何,这里的问题是,您的语法不知道“access”产品的类型;据我所知,这个结果类似于从变量中读取,在解析时变量的类型是未知的。 在我看来,要么放弃100%类型正确的解析,要么找到一种“神奇地”知道变量类型的方法。 您可以跟踪类型声明,并让lexer查找它遇到的变量的类型;然后,lexer将根据变量的类型发送一个变量标识符令牌


我不确定这种方法是否有效,因为我不知道您的语言是什么样子。

为什么要混合解析和键入?我想最好将这个问题作为“为什么不这样做”的一个例子。另外一个例子是menhir而不是ocamlyacc,但有很多次(例如,当你是一名编译器课程的学生时…)你必须使用ocamlyacc,不幸的是:-(@KristopherMicinski:请向您的老师发送反馈,告知您希望使用menhir,甚至是他应该升级课程文件来使用MunHIR,它是我的博士导师,而不是老师……而且我们使用OcAMLACC的原因仅仅是因为我们现在更熟悉它,但是我想我们会考虑尽快切换。
comp_op:
  | bool_expr EQUAL bool_expr  { T.Equiv (T.Wrapper $1, T.Wrapper $3) }
  | num_expr EQUAL num_expr    { T.Equiv (T.Wrapper $1, T.Wrapper $3) }
  /* the wrapper type basically just wraps the expressions to get a common type */

bool_expr:
  | TRUE                       { T.Bool true }
  | FALSE                      { T.Bool false }
  | access                     { T.BoolAccess $1 }

num_expr:
  | NUMBER                     { T.Num $1 }
  | access                     { T.NumAccess $1 }

access:
  /* some more complex rules describing the access to variables */