xref: /aosp_15_r20/external/llvm/examples/OCaml-Kaleidoscope/Chapter7/parser.ml (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker(*===---------------------------------------------------------------------===
2*9880d681SAndroid Build Coastguard Worker * Parser
3*9880d681SAndroid Build Coastguard Worker *===---------------------------------------------------------------------===*)
4*9880d681SAndroid Build Coastguard Worker
5*9880d681SAndroid Build Coastguard Worker(* binop_precedence - This holds the precedence for each binary operator that is
6*9880d681SAndroid Build Coastguard Worker * defined *)
7*9880d681SAndroid Build Coastguard Workerlet binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
8*9880d681SAndroid Build Coastguard Worker
9*9880d681SAndroid Build Coastguard Worker(* precedence - Get the precedence of the pending binary operator token. *)
10*9880d681SAndroid Build Coastguard Workerlet precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
11*9880d681SAndroid Build Coastguard Worker
12*9880d681SAndroid Build Coastguard Worker(* primary
13*9880d681SAndroid Build Coastguard Worker *   ::= identifier
14*9880d681SAndroid Build Coastguard Worker *   ::= numberexpr
15*9880d681SAndroid Build Coastguard Worker *   ::= parenexpr
16*9880d681SAndroid Build Coastguard Worker *   ::= ifexpr
17*9880d681SAndroid Build Coastguard Worker *   ::= forexpr
18*9880d681SAndroid Build Coastguard Worker *   ::= varexpr *)
19*9880d681SAndroid Build Coastguard Workerlet rec parse_primary = parser
20*9880d681SAndroid Build Coastguard Worker  (* numberexpr ::= number *)
21*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Number n >] -> Ast.Number n
22*9880d681SAndroid Build Coastguard Worker
23*9880d681SAndroid Build Coastguard Worker  (* parenexpr ::= '(' expression ')' *)
24*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
25*9880d681SAndroid Build Coastguard Worker
26*9880d681SAndroid Build Coastguard Worker  (* identifierexpr
27*9880d681SAndroid Build Coastguard Worker   *   ::= identifier
28*9880d681SAndroid Build Coastguard Worker   *   ::= identifier '(' argumentexpr ')' *)
29*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Ident id; stream >] ->
30*9880d681SAndroid Build Coastguard Worker      let rec parse_args accumulator = parser
31*9880d681SAndroid Build Coastguard Worker        | [< e=parse_expr; stream >] ->
32*9880d681SAndroid Build Coastguard Worker            begin parser
33*9880d681SAndroid Build Coastguard Worker              | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
34*9880d681SAndroid Build Coastguard Worker              | [< >] -> e :: accumulator
35*9880d681SAndroid Build Coastguard Worker            end stream
36*9880d681SAndroid Build Coastguard Worker        | [< >] -> accumulator
37*9880d681SAndroid Build Coastguard Worker      in
38*9880d681SAndroid Build Coastguard Worker      let rec parse_ident id = parser
39*9880d681SAndroid Build Coastguard Worker        (* Call. *)
40*9880d681SAndroid Build Coastguard Worker        | [< 'Token.Kwd '(';
41*9880d681SAndroid Build Coastguard Worker             args=parse_args [];
42*9880d681SAndroid Build Coastguard Worker             'Token.Kwd ')' ?? "expected ')'">] ->
43*9880d681SAndroid Build Coastguard Worker            Ast.Call (id, Array.of_list (List.rev args))
44*9880d681SAndroid Build Coastguard Worker
45*9880d681SAndroid Build Coastguard Worker        (* Simple variable ref. *)
46*9880d681SAndroid Build Coastguard Worker        | [< >] -> Ast.Variable id
47*9880d681SAndroid Build Coastguard Worker      in
48*9880d681SAndroid Build Coastguard Worker      parse_ident id stream
49*9880d681SAndroid Build Coastguard Worker
50*9880d681SAndroid Build Coastguard Worker  (* ifexpr ::= 'if' expr 'then' expr 'else' expr *)
51*9880d681SAndroid Build Coastguard Worker  | [< 'Token.If; c=parse_expr;
52*9880d681SAndroid Build Coastguard Worker       'Token.Then ?? "expected 'then'"; t=parse_expr;
53*9880d681SAndroid Build Coastguard Worker       'Token.Else ?? "expected 'else'"; e=parse_expr >] ->
54*9880d681SAndroid Build Coastguard Worker      Ast.If (c, t, e)
55*9880d681SAndroid Build Coastguard Worker
56*9880d681SAndroid Build Coastguard Worker  (* forexpr
57*9880d681SAndroid Build Coastguard Worker        ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *)
58*9880d681SAndroid Build Coastguard Worker  | [< 'Token.For;
59*9880d681SAndroid Build Coastguard Worker       'Token.Ident id ?? "expected identifier after for";
60*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '=' ?? "expected '=' after for";
61*9880d681SAndroid Build Coastguard Worker       stream >] ->
62*9880d681SAndroid Build Coastguard Worker      begin parser
63*9880d681SAndroid Build Coastguard Worker        | [<
64*9880d681SAndroid Build Coastguard Worker             start=parse_expr;
65*9880d681SAndroid Build Coastguard Worker             'Token.Kwd ',' ?? "expected ',' after for";
66*9880d681SAndroid Build Coastguard Worker             end_=parse_expr;
67*9880d681SAndroid Build Coastguard Worker             stream >] ->
68*9880d681SAndroid Build Coastguard Worker            let step =
69*9880d681SAndroid Build Coastguard Worker              begin parser
70*9880d681SAndroid Build Coastguard Worker              | [< 'Token.Kwd ','; step=parse_expr >] -> Some step
71*9880d681SAndroid Build Coastguard Worker              | [< >] -> None
72*9880d681SAndroid Build Coastguard Worker              end stream
73*9880d681SAndroid Build Coastguard Worker            in
74*9880d681SAndroid Build Coastguard Worker            begin parser
75*9880d681SAndroid Build Coastguard Worker            | [< 'Token.In; body=parse_expr >] ->
76*9880d681SAndroid Build Coastguard Worker                Ast.For (id, start, end_, step, body)
77*9880d681SAndroid Build Coastguard Worker            | [< >] ->
78*9880d681SAndroid Build Coastguard Worker                raise (Stream.Error "expected 'in' after for")
79*9880d681SAndroid Build Coastguard Worker            end stream
80*9880d681SAndroid Build Coastguard Worker        | [< >] ->
81*9880d681SAndroid Build Coastguard Worker            raise (Stream.Error "expected '=' after for")
82*9880d681SAndroid Build Coastguard Worker      end stream
83*9880d681SAndroid Build Coastguard Worker
84*9880d681SAndroid Build Coastguard Worker  (* varexpr
85*9880d681SAndroid Build Coastguard Worker   *   ::= 'var' identifier ('=' expression?
86*9880d681SAndroid Build Coastguard Worker   *             (',' identifier ('=' expression)?)* 'in' expression *)
87*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Var;
88*9880d681SAndroid Build Coastguard Worker       (* At least one variable name is required. *)
89*9880d681SAndroid Build Coastguard Worker       'Token.Ident id ?? "expected identifier after var";
90*9880d681SAndroid Build Coastguard Worker       init=parse_var_init;
91*9880d681SAndroid Build Coastguard Worker       var_names=parse_var_names [(id, init)];
92*9880d681SAndroid Build Coastguard Worker       (* At this point, we have to have 'in'. *)
93*9880d681SAndroid Build Coastguard Worker       'Token.In ?? "expected 'in' keyword after 'var'";
94*9880d681SAndroid Build Coastguard Worker       body=parse_expr >] ->
95*9880d681SAndroid Build Coastguard Worker      Ast.Var (Array.of_list (List.rev var_names), body)
96*9880d681SAndroid Build Coastguard Worker
97*9880d681SAndroid Build Coastguard Worker  | [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
98*9880d681SAndroid Build Coastguard Worker
99*9880d681SAndroid Build Coastguard Worker(* unary
100*9880d681SAndroid Build Coastguard Worker *   ::= primary
101*9880d681SAndroid Build Coastguard Worker *   ::= '!' unary *)
102*9880d681SAndroid Build Coastguard Workerand parse_unary = parser
103*9880d681SAndroid Build Coastguard Worker  (* If this is a unary operator, read it. *)
104*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Kwd op when op != '(' && op != ')'; operand=parse_expr >] ->
105*9880d681SAndroid Build Coastguard Worker      Ast.Unary (op, operand)
106*9880d681SAndroid Build Coastguard Worker
107*9880d681SAndroid Build Coastguard Worker  (* If the current token is not an operator, it must be a primary expr. *)
108*9880d681SAndroid Build Coastguard Worker  | [< stream >] -> parse_primary stream
109*9880d681SAndroid Build Coastguard Worker
110*9880d681SAndroid Build Coastguard Worker(* binoprhs
111*9880d681SAndroid Build Coastguard Worker *   ::= ('+' primary)* *)
112*9880d681SAndroid Build Coastguard Workerand parse_bin_rhs expr_prec lhs stream =
113*9880d681SAndroid Build Coastguard Worker  match Stream.peek stream with
114*9880d681SAndroid Build Coastguard Worker  (* If this is a binop, find its precedence. *)
115*9880d681SAndroid Build Coastguard Worker  | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
116*9880d681SAndroid Build Coastguard Worker      let token_prec = precedence c in
117*9880d681SAndroid Build Coastguard Worker
118*9880d681SAndroid Build Coastguard Worker      (* If this is a binop that binds at least as tightly as the current binop,
119*9880d681SAndroid Build Coastguard Worker       * consume it, otherwise we are done. *)
120*9880d681SAndroid Build Coastguard Worker      if token_prec < expr_prec then lhs else begin
121*9880d681SAndroid Build Coastguard Worker        (* Eat the binop. *)
122*9880d681SAndroid Build Coastguard Worker        Stream.junk stream;
123*9880d681SAndroid Build Coastguard Worker
124*9880d681SAndroid Build Coastguard Worker        (* Parse the primary expression after the binary operator. *)
125*9880d681SAndroid Build Coastguard Worker        let rhs = parse_unary stream in
126*9880d681SAndroid Build Coastguard Worker
127*9880d681SAndroid Build Coastguard Worker        (* Okay, we know this is a binop. *)
128*9880d681SAndroid Build Coastguard Worker        let rhs =
129*9880d681SAndroid Build Coastguard Worker          match Stream.peek stream with
130*9880d681SAndroid Build Coastguard Worker          | Some (Token.Kwd c2) ->
131*9880d681SAndroid Build Coastguard Worker              (* If BinOp binds less tightly with rhs than the operator after
132*9880d681SAndroid Build Coastguard Worker               * rhs, let the pending operator take rhs as its lhs. *)
133*9880d681SAndroid Build Coastguard Worker              let next_prec = precedence c2 in
134*9880d681SAndroid Build Coastguard Worker              if token_prec < next_prec
135*9880d681SAndroid Build Coastguard Worker              then parse_bin_rhs (token_prec + 1) rhs stream
136*9880d681SAndroid Build Coastguard Worker              else rhs
137*9880d681SAndroid Build Coastguard Worker          | _ -> rhs
138*9880d681SAndroid Build Coastguard Worker        in
139*9880d681SAndroid Build Coastguard Worker
140*9880d681SAndroid Build Coastguard Worker        (* Merge lhs/rhs. *)
141*9880d681SAndroid Build Coastguard Worker        let lhs = Ast.Binary (c, lhs, rhs) in
142*9880d681SAndroid Build Coastguard Worker        parse_bin_rhs expr_prec lhs stream
143*9880d681SAndroid Build Coastguard Worker      end
144*9880d681SAndroid Build Coastguard Worker  | _ -> lhs
145*9880d681SAndroid Build Coastguard Worker
146*9880d681SAndroid Build Coastguard Workerand parse_var_init = parser
147*9880d681SAndroid Build Coastguard Worker  (* read in the optional initializer. *)
148*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Kwd '='; e=parse_expr >] -> Some e
149*9880d681SAndroid Build Coastguard Worker  | [< >] -> None
150*9880d681SAndroid Build Coastguard Worker
151*9880d681SAndroid Build Coastguard Workerand parse_var_names accumulator = parser
152*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Kwd ',';
153*9880d681SAndroid Build Coastguard Worker       'Token.Ident id ?? "expected identifier list after var";
154*9880d681SAndroid Build Coastguard Worker       init=parse_var_init;
155*9880d681SAndroid Build Coastguard Worker       e=parse_var_names ((id, init) :: accumulator) >] -> e
156*9880d681SAndroid Build Coastguard Worker  | [< >] -> accumulator
157*9880d681SAndroid Build Coastguard Worker
158*9880d681SAndroid Build Coastguard Worker(* expression
159*9880d681SAndroid Build Coastguard Worker *   ::= primary binoprhs *)
160*9880d681SAndroid Build Coastguard Workerand parse_expr = parser
161*9880d681SAndroid Build Coastguard Worker  | [< lhs=parse_unary; stream >] -> parse_bin_rhs 0 lhs stream
162*9880d681SAndroid Build Coastguard Worker
163*9880d681SAndroid Build Coastguard Worker(* prototype
164*9880d681SAndroid Build Coastguard Worker *   ::= id '(' id* ')'
165*9880d681SAndroid Build Coastguard Worker *   ::= binary LETTER number? (id, id)
166*9880d681SAndroid Build Coastguard Worker *   ::= unary LETTER number? (id) *)
167*9880d681SAndroid Build Coastguard Workerlet parse_prototype =
168*9880d681SAndroid Build Coastguard Worker  let rec parse_args accumulator = parser
169*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
170*9880d681SAndroid Build Coastguard Worker    | [< >] -> accumulator
171*9880d681SAndroid Build Coastguard Worker  in
172*9880d681SAndroid Build Coastguard Worker  let parse_operator = parser
173*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Unary >] -> "unary", 1
174*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Binary >] -> "binary", 2
175*9880d681SAndroid Build Coastguard Worker  in
176*9880d681SAndroid Build Coastguard Worker  let parse_binary_precedence = parser
177*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Number n >] -> int_of_float n
178*9880d681SAndroid Build Coastguard Worker    | [< >] -> 30
179*9880d681SAndroid Build Coastguard Worker  in
180*9880d681SAndroid Build Coastguard Worker  parser
181*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Ident id;
182*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '(' ?? "expected '(' in prototype";
183*9880d681SAndroid Build Coastguard Worker       args=parse_args [];
184*9880d681SAndroid Build Coastguard Worker       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
185*9880d681SAndroid Build Coastguard Worker      (* success. *)
186*9880d681SAndroid Build Coastguard Worker      Ast.Prototype (id, Array.of_list (List.rev args))
187*9880d681SAndroid Build Coastguard Worker  | [< (prefix, kind)=parse_operator;
188*9880d681SAndroid Build Coastguard Worker       'Token.Kwd op ?? "expected an operator";
189*9880d681SAndroid Build Coastguard Worker       (* Read the precedence if present. *)
190*9880d681SAndroid Build Coastguard Worker       binary_precedence=parse_binary_precedence;
191*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '(' ?? "expected '(' in prototype";
192*9880d681SAndroid Build Coastguard Worker        args=parse_args [];
193*9880d681SAndroid Build Coastguard Worker       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
194*9880d681SAndroid Build Coastguard Worker      let name = prefix ^ (String.make 1 op) in
195*9880d681SAndroid Build Coastguard Worker      let args = Array.of_list (List.rev args) in
196*9880d681SAndroid Build Coastguard Worker
197*9880d681SAndroid Build Coastguard Worker      (* Verify right number of arguments for operator. *)
198*9880d681SAndroid Build Coastguard Worker      if Array.length args != kind
199*9880d681SAndroid Build Coastguard Worker      then raise (Stream.Error "invalid number of operands for operator")
200*9880d681SAndroid Build Coastguard Worker      else
201*9880d681SAndroid Build Coastguard Worker        if kind == 1 then
202*9880d681SAndroid Build Coastguard Worker          Ast.Prototype (name, args)
203*9880d681SAndroid Build Coastguard Worker        else
204*9880d681SAndroid Build Coastguard Worker          Ast.BinOpPrototype (name, args, binary_precedence)
205*9880d681SAndroid Build Coastguard Worker  | [< >] ->
206*9880d681SAndroid Build Coastguard Worker      raise (Stream.Error "expected function name in prototype")
207*9880d681SAndroid Build Coastguard Worker
208*9880d681SAndroid Build Coastguard Worker(* definition ::= 'def' prototype expression *)
209*9880d681SAndroid Build Coastguard Workerlet parse_definition = parser
210*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
211*9880d681SAndroid Build Coastguard Worker      Ast.Function (p, e)
212*9880d681SAndroid Build Coastguard Worker
213*9880d681SAndroid Build Coastguard Worker(* toplevelexpr ::= expression *)
214*9880d681SAndroid Build Coastguard Workerlet parse_toplevel = parser
215*9880d681SAndroid Build Coastguard Worker  | [< e=parse_expr >] ->
216*9880d681SAndroid Build Coastguard Worker      (* Make an anonymous proto. *)
217*9880d681SAndroid Build Coastguard Worker      Ast.Function (Ast.Prototype ("", [||]), e)
218*9880d681SAndroid Build Coastguard Worker
219*9880d681SAndroid Build Coastguard Worker(*  external ::= 'extern' prototype *)
220*9880d681SAndroid Build Coastguard Workerlet parse_extern = parser
221*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Extern; e=parse_prototype >] -> e
222