首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >FsLex FsYacc:如何创建具有多行注释的语言

FsLex FsYacc:如何创建具有多行注释的语言
EN

Stack Overflow用户
提问于 2015-10-25 16:45:45
回答 1查看 506关注 0票数 0

我正在玩FsLex和FsYacc,它们是基于ocamllex和ocamlyacc的。在语言中定义注释的最佳方法是什么?我是否在我的lex文件中创建注释令牌?有几个复杂的评论,我不能把我的头围绕在一个语法的上下文:

  1. 注释可以放在语法的任何地方,应该被忽略。
  2. 注释可以包含任何内容,包括其他标记和无效代码。
  3. 注释可以跨越许多行,我需要维护调试器的源代码位置。在FsLex和ocamllex中,这必须由语言开发人员来完成。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-25 17:12:51

由于您包含了ocaml标记,所以我将回答ocamllex

的确,处理注释是很困难的,特别是如果您的语言希望能够注释掉部分代码的话。在这种情况下,注释lexer必须在注释中查找(一组减少的)标记,以免被引用上下文中的注释闭包所愚弄。这也意味着lexer应该遵循注释的嵌套,所以注释掉的注释不会混淆事情。

OCaml编译器本身就是这种方法的一个例子。OCaml编译器的注释处理有三部分。第一级词法规则如下所示:

代码语言:javascript
复制
rule main = parse

    . . . code omitted here . . .

    | "(*"
      { comment_depth := 1;
        handle_lexical_error comment lexbuf;
        main lexbuf }

第二级由函数handle_lexical_error和函数comment组成。前者在捕获特定异常时计算一个lexing函数。后者是注释的详细词法函数。在注释的词法之后,上面的代码返回到常规的词法(使用main lexbuf)。

函数comment如下所示:

代码语言:javascript
复制
rule comment = parse
    "(*"
    { incr comment_depth; comment lexbuf }
  | "*)"
    { decr comment_depth;
      if !comment_depth = 0 then () else comment lexbuf }
  | '"'
    { reset_string_buffer();
      string lexbuf;
      reset_string_buffer();
      comment lexbuf }
  | "'"
    { skip_char lexbuf ;
     comment lexbuf }
  | eof
    { raise(Lexical_error("unterminated comment", "", 0, 0)) }
  | '\010'
    { incr_loc lexbuf 0;
      comment lexbuf }
  | _
    { comment lexbuf }

所以,是的,把工作做好是相当复杂的。

对于最后一点,ocamllex自动跟踪源代码位置。你可以从莱布夫那里找到它们。请参阅OCaml Lexing模块。(但是,请注意,上面的注释词法函数在对换行符进行调整时会调整位置。) incr_loc函数增加跟踪行号。)

我不知道F#跟踪这个设计有多近,但希望这会有所帮助。

更新

下面是string的词法函数:

代码语言:javascript
复制
rule string = parse
    '"'
    { () }
   | '\\' ("\010" | "\013" | "\013\010") ([' ' '\009'] * as spaces)
    { incr_loc lexbuf (String.length spaces);
      string lexbuf }
  | '\\' (backslash_escapes as c)
    { store_string_char(char_for_backslash c);
      string lexbuf }
  | '\\' (['0'-'9'] as c) (['0'-'9'] as d) (['0'-'9']  as u)
    { let v = decimal_code c d u in
      if in_pattern () && v > 255 then
       warning lexbuf
        (Printf.sprintf
          "illegal backslash escape in string: `\\%c%c%c'" c d u) ;
      store_string_char (Char.chr v);
      string lexbuf }
 | '\\' 'x' (['0'-'9' 'a'-'f' 'A'-'F'] as d) (['0'-'9' 'a'-'f' 'A'-'F'] as u)   
    { store_string_char (char_for_hexadecimal_code d u) ;
      string lexbuf }
  | '\\' (_ as c) 
    {if in_pattern () then
       warning lexbuf
        (Printf.sprintf "illegal backslash escape in string: `\\%c'" c) ;
      store_string_char '\\' ;
      store_string_char c ;
      string lexbuf }
  | eof
    { raise(Lexical_error("unterminated string", "", 0, 0)) }
  | '\010'
    { store_string_char '\010';
      incr_loc lexbuf 0;
      string lexbuf }
  | _ as c
    { store_string_char c;
      string lexbuf }

如果您想了解更多信息,您可以在这里找到完整的OCaml lexer源:lexer.mll

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

https://stackoverflow.com/questions/33332251

复制
相关文章

相似问题

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