如何创建带有多行注释的语言



我正在玩FsLex和FsYacc,这是基于ocamllex和ocamlyacc。在语言中定义注释的最佳方式是什么?我要在lex文件中创建注释令牌吗?有一些复杂的注释,在语法上下文中我无法理解:

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

既然您包含了ocaml标签,我将回答ocamllex

处理注释确实很困难,特别是如果你的语言希望能够注释掉代码部分。在这种情况下,注释词法分析器必须在注释中查找(简化的)令牌,以免被出现在引号上下文中的注释闭包所欺骗。这也意味着词法分析器应该遵循注释的嵌套,这样注释掉的注释就不会混淆了。

OCaml编译器本身就是这种方法的一个例子。OCaml编译器的注释处理有三个部分。第一级词法分析规则如下所示:
rule main = parse
    . . . code omitted here . . .
    | "(*"
      { comment_depth := 1;
        handle_lexical_error comment lexbuf;
        main lexbuf }

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

函数comment看起来像这样:

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)) }
  | '10'
    { incr_loc lexbuf 0;
      comment lexbuf }
  | _
    { comment lexbuf }

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

对于最后一点,ocamllex自动为您跟踪源代码位置。您可以从lexbuf中检索它们。参见OCaml Lexing模块。(但是,请注意,上面的注释词法分析函数在词法分析换行符时调整位置。incr_loc函数增加跟踪的行号)

我不确定f#如何密切跟踪这种设计,但希望这将是有帮助的。

以下是string词法分析函数:
rule string = parse
    '"'
    { () }
   | '\' ("10" | "13" | "1310") ([' ' '09'] * 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)) }
  | '10'
    { store_string_char '10';
      incr_loc lexbuf 0;
      string lexbuf }
  | _ as c
    { store_string_char c;
      string lexbuf }

如果您想了解更多信息,可以在这里找到完整的OCaml词法分析器源代码:lexer.mll.

最新更新