Parsing 在特殊情况下进一步解析表达式

Parsing 在特殊情况下进一步解析表达式,parsing,ocaml,frontend,lexer,Parsing,Ocaml,Frontend,Lexer,目前,我的前端可以解析正常表达式,如123,“abcd”,“=123”,“=TRUE+123”。。。以下是相关代码: (* in `syntax.ml`: *) and expression = | E_integer of int | E_string of string (* in `parser.mly`: *) expression: | INTEGER { E_integer $1 } | STRING { E_string $1 } 现在我想改进解析器,这样,

目前,我的前端可以解析正常表达式,如
123
“abcd”
“=123”
“=TRUE+123”
。。。以下是相关代码:

(* in `syntax.ml`: *)
and expression =
  | E_integer of int  
  | E_string of string

(* in `parser.mly`: *)
expression:
  | INTEGER { E_integer $1 }
  | STRING { E_string $1 }
现在我想改进解析器,这样,当我们遇到一个以
=
开头的字符串时,我们会尝试将其作为一个公式来计算,而不是一个文本字符串。所以
syntax.ml
变成:

(* in `syntax.ml`: *)
and expression =
  | E_integer of int  
  | E_string of string
  | E_formula of formula

and formula =
  | F_integer of int  
  | F_boolean of bool
  | F_Add of formula * formula
问题是我不确定如何更改
parser.mly
,我尝试了此操作,但无效(
此表达式具有类型字符串,但表达式应为类型语法。公式
):

我想我可以在这里直接做一些事情:

let STRING = double_quote ([^ '\x0D' '\x0A' '\x22'])* double_quote    
let FORMULA_STRING = double_quote = ([^ '\x0D' '\x0A' '\x22'])* double_quote
rule token = parse
  | FORMULA_STRING as fs { XXXXX }
  | STRING as s { STRING s }

如果我有单独的
Parser\u formula.mly
,我不确定我应该在
XXXXX
处写什么,应该是
Parser\u formula.formula token fs
?如果我只有
parser.mly
,它包含了所有的语法,包括公式中的语法,那该怎么办?

问题在于你的行

    else E_formula (String.sub $1 2 ((String.length $1) - 1))
您应该返回类型为
Syntax.formula
的值,而不是类型为
(String.sub…
)的
(String.sub…
)。如果您有一个
parse_formula:string->Syntax.formula
函数,您可以在这里编写

    else E_formula (parse_formula (String.sub $1 2 ((String.length $1) - 1)))
我认为可以通过首先将公式语法定义为单独的解析器来定义这样一个函数

编辑:以下是您自己的编辑:

  • 如果您选择为公式调用不同的解析器,则不需要定义不同的lexer

  • 如果您选择在lexer级别处理字符串和公式之间的区别(您确定这是正确的吗?以“=”开头的真实字符串呢?),那么您不需要为公式使用单独的解析器,您可以在当前语法中将它们作为规则使用。但要做到这一点,您需要您的lexer以更细粒度的方式处理公式:您不应该仅仅将
    “=.*”
    识别为单个标记,而应该将
    “=
    识别为公式的开始,并将公式的其余部分lex化,直到遇到结束
    。为了避免冲突,您可能希望使用词法规则而不是简单的regexp来处理简单字符串

如果你能采用第二种方法,我认为这确实是一个更简单的想法


PS:如果变量不连续(因为中间终端),或者您需要重复多次,请使用menhir变量命名工具,而不是
$1

继续@gasche的回答

您希望在解析器中包含新的语法规则,这意味着您需要在parser.mly中更改语法规则以适应这些新规则

String.sub
方法在某种程度上是正确的,但实际上您是在手工完成mly文件可以让您自动化的工作

考虑您的
公式
类型:这里的
F_Add
数据类型允许您编码一个二进制和公式,因此包含两个公式。 在mly文件中,您可以将其描述为:

formula:
   INTEGER                              { F_Integer $1 }
  | BOOL                                   { F_Bool $1 }
  | formula PLUS formula   { F_Add ($1, $3) }
;
注意语法规则定义如何反映
公式
类型定义。 如您所见,公式的递归属性由语法规则很好地处理

关于
lexer.mll
,正则表达式
STRING
FORMULA\u STRING
完全相同。如果在同一个lexer规则中同时使用它们(就像在代码段中一样),那么它将无法按预期工作。词法分析器不知道解析器中发生了什么,当解析器方便填写特定规则时,它不能选择提供
字符串或
公式字符串。使用ocamlyacc(以及它从中获得灵感的工具),它的工作方式是相反的:解析器从文本流中接收词法分析器已经识别的标记,并根据他之前已经发现的内容,尝试找到与它们对应的规则

请注意,
BOOL
终端必须由_lexer.mll
重新定义(就像
INTEGER`),因此需要使用适当的正则表达式对其进行修改

此外,你应该问自己以下问题: 在
=5
公式中,是否有一个表达式等待发现


如果是这样,您能否根据表达式和新标记重新定义公式?

5被视为
表达式
;虽然<代码>“5”<代码>被认为是<代码>公式< /代码>。我采用第二种方法,目前我只考虑所有字符串以“=”公式开始。谢谢
    else E_formula (parse_formula (String.sub $1 2 ((String.length $1) - 1)))
formula:
   INTEGER                              { F_Integer $1 }
  | BOOL                                   { F_Bool $1 }
  | formula PLUS formula   { F_Add ($1, $3) }
;