我正在玩FsLex和FsYacc,它基于ocamllex和ocamlyacc。在语言中定义注释的最佳方法是什么?我在lex文件中创建注释标记吗?评论有一些复杂性,我无法在语法的上下文中解决这个问题:
答案 0 :(得分:2)
由于您添加了ocaml
代码,我会回答ocamllex
。
处理评论很困难,特别是如果您的语言希望能够注释掉代码段。在这种情况下,注释词法分析器必须在注释中查找(减少的一组)标记,以免被引用的上下文中出现的注释闭包所欺骗。这也意味着词法分析者应该遵循评论的嵌套,因此评论出来的评论不会让事情变得混乱。
OCaml编译器本身就是这种方法的一个例子。 OCaml编译器的注释处理有三个部分。第一级lexing规则如下:
rule main = parse
. . . code omitted here . . .
| "(*"
{ comment_depth := 1;
handle_lexical_error comment lexbuf;
main lexbuf }
第二级包含函数handle_lexical_error
和函数comment
。前者在捕获特定异常时评估lexing函数。后者是评论的详细lexing功能。在评论之后,上面的代码会回到常规的lexing(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)) }
| '\010'
{ incr_loc lexbuf 0;
comment lexbuf }
| _
{ comment lexbuf }
所以,是的,做好工作非常复杂。
最后一点,ocamllex
会自动跟踪您的源代码位置。您可以从lexbuf中检索它们。请参阅OCaml Lexing
模块。 (但是请注意,上面的注释lexing函数会在修改换行符时调整位置。incr_loc
函数会增加跟踪的行号。)
我不确定F#跟踪这个设计有多紧密,但希望这会有所帮助。
<强>更新强>
这是string
lexing函数:
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.mll。