首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用OcamlYacc / FsYacc表示可选语法和重复

用OcamlYacc / FsYacc表示可选语法和重复
EN

Stack Overflow用户
提问于 2009-02-10 19:31:12
回答 2查看 1.1K关注 0票数 3

我正在努力积累一些语法分析/语法分析方面的技能。我回顾了我为SQL编写的一个简单的解析器,我对它并不完全满意--似乎应该有一种更简单的方法来编写解析器。

SQL绊倒了我,因为它有很多可选的标记和重复。例如:

代码语言:javascript
复制
SELECT *
FROM t1
INNER JOIN t2
INNER JOIN t3
WHERE t1.ID = t2.ID and t1.ID = t3.ID

相当于:

代码语言:javascript
复制
SELECT *
FROM t1
INNER JOIN t2 ON t1.ID = t2.ID
INNER JOIN t3 on t1.ID = t3.ID

ONWHERE子句是可选的,可以发生不止一次。我在解析器中处理了这些问题,如下所示:

代码语言:javascript
复制
%{
open AST
%}

// ...    
%token <string> ID   
%token AND OR COMMA
%token EQ LT LE GT GE
%token JOIN INNER LEFT RIGHT ON
// ...

%%

op: EQ { Eq } | LT { Lt } | LE { Le } | GT { Gt } | GE { Ge }

// WHERE clause is optional    
whereClause:
    |                       { None }
    | WHERE whereList       { Some($2) }        

whereList:
    | ID op ID                    { Cond($1, $2, $3) }
    | ID op ID AND whereList      { And(Cond($1, $2, $3), $5) }
    | ID op ID OR whereList       { Or(Cond($1, $2, $3), $5) }


// Join clause is optional    
joinList:
    |                       { [] }
    | joinClause            { [$1] }
    | joinClause joinList   { $1 :: $2 }

joinClause:
    | INNER JOIN ID joinOnClause    { $3, Inner, $4 }
    | LEFT JOIN ID joinOnClause     { $3, Left, $4 }
    | RIGHT JOIN ID joinOnClause    { $3, Right, $4 }

// "On" clause is optional    
joinOnClause:
    |                       { None }
    | ON whereList          { Some($2) }

// ...
%%

换句话说,我通过将可选语法分解成单独的规则来处理可选语法,并使用递归处理重复。这是可行的,但它将解析分解为一组小的子程序,很难看出语法到底代表了什么。

我认为,如果我可以在括号内指定可选语法并使用*或+来重复,那么编写起来就容易多了。这将将我的whereClause和joinList规则简化为以下内容:

代码语言:javascript
复制
whereClause:
    |                       { None }
//    $1    $2, I envision $2 being return as an (ID * op * ID * cond) list
    | WHERE [ ID op ID { (AND | OR) }]+
        { Some([for name1, op, name2, _ in $1 -> name1, op, name2]) }

joinClause:
    |                       { None }

//    $1, returned as (joinType
//                       * JOIN
//                       * ID
//                       * ((ID * op * ID) list) option) list
    | [ (INNER | LEFT | RIGHT) JOIN ID [ON whereClause] ]*
        { let joinType, _, table, onClause = $1;
          Some(table, joinType, onClause) }

我认为这种形式是,更易于阅读和表达它试图更直观地捕捉到的语法。不幸的是,我在Ocaml或F#文档中找不到任何支持这种表示法或类似符号的东西。

是否有一种简单的方法可以用OcamlYacc或FsYacc?中的可选或重复标记来表示语法

EN

回答 2

Stack Overflow用户

发布于 2009-02-10 20:25:48

当你完成所有的小作品时,你应该得到你想要的东西。而不是:

代码语言:javascript
复制
(INNER | RIGHT | LEFT ) 

你刚刚

代码语言:javascript
复制
inner_right_left

把它定义为这三个关键词的结合。

还可以在lexer中定义联合。按照您定义令牌的方式,或者使用camlp4,我在这方面没有做太多工作,所以我不能建议您选择这些路线。我不认为他们会为你工作,就像到处都有小碎片一样。

编辑:

因此,对于camlp4,您可以查看Camlp4语法模教程更好的教程。这不是你想要的,请注意,但它是相当接近。文档非常糟糕,正如在关于ocaml群的最新讨论中所表达的那样,但是对于这个特定的领域,我认为您不会有太多的问题。我做了一点,可以提出更多的问题。

票数 3
EN

Stack Overflow用户

发布于 2009-06-26 09:28:14

门希尔允许用另一个符号参数化非终端符号,并提供标准快捷方式库,如选项和列表,您可以创建自己的快捷键。示例:

代码语言:javascript
复制
option(X): x=X { Some x} 
         | { None }

还有一些语法糖,‘令牌?’等于“token+”到“nonempty_list(令牌)”。

所有这些都大大缩短了语法定义。此外,它是由ocamlbuild支持的,并且可以作为ocamlyacc的插入替代。强烈推荐!

有趣的是,我也用它来解析SQL :)

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/533808

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档