我正在尝试遵循Appel的"ML中的现代编译器实现",并且正在使用Ocamllex编写词法分析器.
规范要求词法分析器在转换转义序列后返回字符串.以下代码摘自ocamllex输入文件:
rule tiger = parse
...
| '"'
{ let buffer = Buffer.create 1 in
STRING (stringl buffer lexbuf)
}
and stringl buffer = parse
| '"' { Buffer.contents buffer }
| "\\t" { Buffer.add_char buffer '\t'; stringl buffer lexbuf }
| "\\n" { Buffer.add_char buffer '\n'; stringl buffer lexbuf }
| "\\n" { Buffer.add_char buffer '\n'; stringl buffer lexbuf }
| '\\' '"' { Buffer.add_char buffer '"'; stringl buffer lexbuf }
| '\\' '\\' …
Run Code Online (Sandbox Code Playgroud) 有没有办法在OCamlLex中返回多个令牌?
我正在尝试为基于缩进的语言编写词法分析器和解析器,并且当我DEDENT
注意到缩进级别比以前更小时,我希望我的词法分析器返回多个标记.这将允许它在多个块结束时通知解析器.
按照此方法,我将能够使用INDENT
并DEDENT
作为插入式替代BEGIN
和END
,因为这两个标记将被暗示INDENT
和DEDENT
令牌.
我在业余时间一直在研究Lua fslex lexer,使用ocamllex手册作为参考.
我试图正确地标记长字符串时遇到了一些障碍."长串"由'[' ('=')* '['
和']' ('=')* ']'
令牌分隔; =
标志的数量必须相同.
在第一个实现中,词法分析器似乎无法识别[[
模式,LBRACKET
尽管匹配规则最长,但产生两个令牌,而[=[
正确识别的变量则产生两个令牌.此外,正则表达式无法确保使用正确的结束标记']' ('=')* ']'
,无论实际的长字符串"级别"如何,都会在第一次捕获时停止.此外,fslex似乎不支持正则表达式中的"as"结构.
let lualongstring = '[' ('=')* '[' ( escapeseq | [^ '\\' '[' ] )* ']' ('=')* ']'
(* ... *)
| lualongstring { (* ... *) }
| '[' { LBRACKET }
| ']' { RBRACKET }
(* ... *)
我一直试图用词法分析器中的另一个规则来解决这个问题:
rule tokenize = parse
(* ... *)
| '[' ('=')* '[' { longstring (getLongStringLevel(lexeme …
Run Code Online (Sandbox Code Playgroud) 我正在用 ocamllex 在 OCaml 中编写一种玩具编程语言,并试图使该语言对缩进更改敏感,python 风格,但在将行开头与 ocamllex 的正则表达式规则匹配时遇到问题。我习惯使用^
来匹配行的开头,但在 OCaml 中这是字符串连接运算符。不幸的是,谷歌搜索对我来说并没有出现太多:(有人知道这是如何工作的吗?
我正在使用ocamllex为脚本语言编写词法分析器,但我面临与我的评论规则的冲突.
我希望允许我的命令参数不加引号,只要它们只包含字母数字字符和斜杠"/"即可.例如:
echo "quoted argument !@#%" /this/second/argument/is/unquoted
Run Code Online (Sandbox Code Playgroud)
另外,我的一个先决条件是带有"//"的C++样式注释
//this is a comment
echo hello world
Run Code Online (Sandbox Code Playgroud)
这带来的问题是这样的
echo foo//comment
Run Code Online (Sandbox Code Playgroud)
我希望我的词法分析器产生一个"foo"令牌,同时也保持"//"不变,以便在下次我向词法分析器询问令牌时使用它.那可能吗?这样做的原因是输入缓冲区可能还没有到达注释的末尾,我宁愿立即返回"foo"令牌而不是不必要地阻止尝试急切地使用注释.
我正在用Menhir + Ocamllex写一个小解析器,我有两个要求,我似乎无法同时满足
我只能通过使用error
令牌轻松地做到1).我也可以使用针对此问题建议的方法轻松地做到2).但是,我不知道实现这两者的简单方法.
我现在处理错误的方式是这样的:
pair:
| left = prodA SEPARATOR right = prodA { (* happy case *) }
| error SEPARATOR right = prodA { print_error_report $startpos;
(* would like to continue after the first error, just in case
there is a second error, so I report both *) }
Run Code Online (Sandbox Code Playgroud)
有一件事可以帮助我访问lexbuf本身,所以我可以直接获得令牌.这将意味着,而不是$startpos
我传的东西一样 $lexbuf
,但据我所知,有访问lexbuf没有官方途径.1中的解决方案仅在解析器的调用者级别工作,其中调用者本身将lexbuf传递给解析器,但不在语义操作中.
有谁知道它是否真的以某种方式可用?或者可能是一种解决方法?
我在这里结束了.我无法在ocamllex工作,它让我疯了.这是我的.mll
档案:
{
open Parser
}
rule next = parse
| (['a'-'z'] ['a'-'z']*) as id { Identifier id }
| '=' { EqualsSign }
| ';' { Semicolon }
| '\n' | ' ' { next lexbuf }
| eof { EOF }
Run Code Online (Sandbox Code Playgroud)
以下是我作为输入传入的文件的内容:
a=b;
Run Code Online (Sandbox Code Playgroud)
然而,当我编译并运行该东西时,我在第一个字符上出现错误,说它无效.老实说,我不知道发生了什么,谷歌根本没有帮助我.这怎么可能呢?如你所见,我真的很难过.
编辑:
我工作了很长时间,以至于我放弃了解析器.现在这是我的主文件中的相关代码:
let parse_file filename =
let l = Lexing.from_channel (open_in filename) in
try
Lexer.next l; ()
with
| Failure msg ->
printf "line: %d, col: %d\n" l.lex_curr_p.pos_lnum l.lex_curr_p.pos_cnum
Run Code Online (Sandbox Code Playgroud)
打印出"line:1,col:1".
我的OCaml .ml代码如下所示:
open Str
let idregex = Str.regexp ['a'-'z' 'A'-'Z']+ ['a'-'z' 'A'-'Z' '0'-'9' '_']*;
let evalT (x,y) = (match x with
Str.regexp "Id(" (idregex as var) ")" -> (x,y)
Run Code Online (Sandbox Code Playgroud)
为什么上面的代码不起作用?我怎样才能让它发挥作用?
编辑:
我不需要做很多解析.所以,我希望它保留在OCaml .ml文件而不是OCamllex文件中
有没有办法在Ocamllex规范中使用大小写敏感令牌?我已经尝试以这种方式创建大小写敏感令牌:
let token = parser
...
| ['C''c']['A''a']['S''s']['E''e'] { CASE }
...
Run Code Online (Sandbox Code Playgroud)
但我正在寻找别的东西,如果存在的话.
我目前正在编写一种编程语言作为业余爱好.如果有可能让ocamllex打印出它匹配的标记,它会使lexing错误更容易调试,我偶尔会手动将print语句添加到我的规则中,但应该有一种更简单的方法.
所以我要问的是,给定.mll文件和一些输入,是否有自动方式查看相应的令牌?