parser.mly:
%{
let env=Hashtbl.create 10
%}
%token <int> INT
%token SUB
%token EOL
%token EQUAL
%token NAME
%left SUB EQUAL
%start main /* the entry point */
%type<int> main
%%
main:
expr EOL { $1 }
;
expr:
INT { $1}
| expr SUB expr { $1 - $3}
| var EQUAL expr {Hashtbl.add env $1 $3;0}
| var {Hashtbl.find env $1}
;
var:NAME {$1}
(12 行是:
%type<int> main
)
使用:
wangkai@wangkai-ThinkPad-X1:~/src/ocaml/lexonlysub$ ./calc
a=1
0
b=2
0
b
2
a
2
^C
我不知道为什么定义b=2后,a也是2,应该是1。为什么是2?
还有这个:
wangkai@wangkai-ThinkPad-X1:~/src/ocaml/lexonlysub$ ./calc
a=1
0
b=2
0
a-b
0
lexer.mll:
{
open Parser
exception Eof
}
rule token = parse
[' ' '\t'] { token lexbuf } (* skip blanks *)
| ['\n' ] { EOL }
| ['0'-'9']+ as lxm { INT(int_of_string lxm) }
| '-' { SUB }
|['a'-'z']+ {NAME}
|'=' {EQUAL}
| eof { raise Eof }
谢谢!
计算.ml
开放语法 让_ = 尝试 让 lexbuf = Lexing.from_channel stdin 中 虽然是真的 让结果 = Parser.main Lexer.token lexbuf in print_int 结果; print_newline();刷新标准输出 完毕 与 Lexer.Eof -> 出口0
生成文件:
calc:lexer.cmo 解析器.cmo 语法.cmo calc.cmo ocamlc -o calc lexer.cmo 解析器.cmo 语法.cmo calc.cmo 词法分析器.cmo:词法分析器.mll ocamllex 词法分析器.mll 解析器.cmo:解析器.mly 门希尔解析器.mly 语法.cmo:语法.ml ocamlc -c 语法.ml 计算.cmo:计算.ml ocamlc -c 词法分析器.ml ocamlc -c 解析器.mli ocamlc -c 解析器.ml ocamlc -c calc.ml
您需要向
NAME
添加有效负载。否则,它不会注册词法分析的字符串;相反,它给你的值只是 ()
,所以每次你访问哈希表时,你都会访问相同的元素。
您需要将
string
类型添加到 NAME
:
%token<string> NAME
拥有
string
有效负载。您还需要实际记住词法分析器中的有效负载:
| ['a'-'z']+ as name { NAME(name) }
(这两个片段应该替换代码中的等效片段)
您可以通过添加一些注释来确保您拥有合适的类型:
%{
let env : (string, int) Hashtbl.t = Hashtbl.create 10
%}
(如果您将此注释添加到当前版本,它应该会失败;但如果将适当的有效负载添加到
NAME
,则不会失败)。