xref: /aosp_15_r20/external/llvm/examples/OCaml-Kaleidoscope/Chapter5/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 Workerlet rec parse_primary = parser
19*9880d681SAndroid Build Coastguard Worker  (* numberexpr ::= number *)
20*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Number n >] -> Ast.Number n
21*9880d681SAndroid Build Coastguard Worker
22*9880d681SAndroid Build Coastguard Worker  (* parenexpr ::= '(' expression ')' *)
23*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
24*9880d681SAndroid Build Coastguard Worker
25*9880d681SAndroid Build Coastguard Worker  (* identifierexpr
26*9880d681SAndroid Build Coastguard Worker   *   ::= identifier
27*9880d681SAndroid Build Coastguard Worker   *   ::= identifier '(' argumentexpr ')' *)
28*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Ident id; stream >] ->
29*9880d681SAndroid Build Coastguard Worker      let rec parse_args accumulator = parser
30*9880d681SAndroid Build Coastguard Worker        | [< e=parse_expr; stream >] ->
31*9880d681SAndroid Build Coastguard Worker            begin parser
32*9880d681SAndroid Build Coastguard Worker              | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
33*9880d681SAndroid Build Coastguard Worker              | [< >] -> e :: accumulator
34*9880d681SAndroid Build Coastguard Worker            end stream
35*9880d681SAndroid Build Coastguard Worker        | [< >] -> accumulator
36*9880d681SAndroid Build Coastguard Worker      in
37*9880d681SAndroid Build Coastguard Worker      let rec parse_ident id = parser
38*9880d681SAndroid Build Coastguard Worker        (* Call. *)
39*9880d681SAndroid Build Coastguard Worker        | [< 'Token.Kwd '(';
40*9880d681SAndroid Build Coastguard Worker             args=parse_args [];
41*9880d681SAndroid Build Coastguard Worker             'Token.Kwd ')' ?? "expected ')'">] ->
42*9880d681SAndroid Build Coastguard Worker            Ast.Call (id, Array.of_list (List.rev args))
43*9880d681SAndroid Build Coastguard Worker
44*9880d681SAndroid Build Coastguard Worker        (* Simple variable ref. *)
45*9880d681SAndroid Build Coastguard Worker        | [< >] -> Ast.Variable id
46*9880d681SAndroid Build Coastguard Worker      in
47*9880d681SAndroid Build Coastguard Worker      parse_ident id stream
48*9880d681SAndroid Build Coastguard Worker
49*9880d681SAndroid Build Coastguard Worker  (* ifexpr ::= 'if' expr 'then' expr 'else' expr *)
50*9880d681SAndroid Build Coastguard Worker  | [< 'Token.If; c=parse_expr;
51*9880d681SAndroid Build Coastguard Worker       'Token.Then ?? "expected 'then'"; t=parse_expr;
52*9880d681SAndroid Build Coastguard Worker       'Token.Else ?? "expected 'else'"; e=parse_expr >] ->
53*9880d681SAndroid Build Coastguard Worker      Ast.If (c, t, e)
54*9880d681SAndroid Build Coastguard Worker
55*9880d681SAndroid Build Coastguard Worker  (* forexpr
56*9880d681SAndroid Build Coastguard Worker        ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *)
57*9880d681SAndroid Build Coastguard Worker  | [< 'Token.For;
58*9880d681SAndroid Build Coastguard Worker       'Token.Ident id ?? "expected identifier after for";
59*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '=' ?? "expected '=' after for";
60*9880d681SAndroid Build Coastguard Worker       stream >] ->
61*9880d681SAndroid Build Coastguard Worker      begin parser
62*9880d681SAndroid Build Coastguard Worker        | [<
63*9880d681SAndroid Build Coastguard Worker             start=parse_expr;
64*9880d681SAndroid Build Coastguard Worker             'Token.Kwd ',' ?? "expected ',' after for";
65*9880d681SAndroid Build Coastguard Worker             end_=parse_expr;
66*9880d681SAndroid Build Coastguard Worker             stream >] ->
67*9880d681SAndroid Build Coastguard Worker            let step =
68*9880d681SAndroid Build Coastguard Worker              begin parser
69*9880d681SAndroid Build Coastguard Worker              | [< 'Token.Kwd ','; step=parse_expr >] -> Some step
70*9880d681SAndroid Build Coastguard Worker              | [< >] -> None
71*9880d681SAndroid Build Coastguard Worker              end stream
72*9880d681SAndroid Build Coastguard Worker            in
73*9880d681SAndroid Build Coastguard Worker            begin parser
74*9880d681SAndroid Build Coastguard Worker            | [< 'Token.In; body=parse_expr >] ->
75*9880d681SAndroid Build Coastguard Worker                Ast.For (id, start, end_, step, body)
76*9880d681SAndroid Build Coastguard Worker            | [< >] ->
77*9880d681SAndroid Build Coastguard Worker                raise (Stream.Error "expected 'in' after for")
78*9880d681SAndroid Build Coastguard Worker            end stream
79*9880d681SAndroid Build Coastguard Worker        | [< >] ->
80*9880d681SAndroid Build Coastguard Worker            raise (Stream.Error "expected '=' after for")
81*9880d681SAndroid Build Coastguard Worker      end stream
82*9880d681SAndroid Build Coastguard Worker
83*9880d681SAndroid Build Coastguard Worker  | [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
84*9880d681SAndroid Build Coastguard Worker
85*9880d681SAndroid Build Coastguard Worker(* binoprhs
86*9880d681SAndroid Build Coastguard Worker *   ::= ('+' primary)* *)
87*9880d681SAndroid Build Coastguard Workerand parse_bin_rhs expr_prec lhs stream =
88*9880d681SAndroid Build Coastguard Worker  match Stream.peek stream with
89*9880d681SAndroid Build Coastguard Worker  (* If this is a binop, find its precedence. *)
90*9880d681SAndroid Build Coastguard Worker  | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
91*9880d681SAndroid Build Coastguard Worker      let token_prec = precedence c in
92*9880d681SAndroid Build Coastguard Worker
93*9880d681SAndroid Build Coastguard Worker      (* If this is a binop that binds at least as tightly as the current binop,
94*9880d681SAndroid Build Coastguard Worker       * consume it, otherwise we are done. *)
95*9880d681SAndroid Build Coastguard Worker      if token_prec < expr_prec then lhs else begin
96*9880d681SAndroid Build Coastguard Worker        (* Eat the binop. *)
97*9880d681SAndroid Build Coastguard Worker        Stream.junk stream;
98*9880d681SAndroid Build Coastguard Worker
99*9880d681SAndroid Build Coastguard Worker        (* Parse the primary expression after the binary operator. *)
100*9880d681SAndroid Build Coastguard Worker        let rhs = parse_primary stream in
101*9880d681SAndroid Build Coastguard Worker
102*9880d681SAndroid Build Coastguard Worker        (* Okay, we know this is a binop. *)
103*9880d681SAndroid Build Coastguard Worker        let rhs =
104*9880d681SAndroid Build Coastguard Worker          match Stream.peek stream with
105*9880d681SAndroid Build Coastguard Worker          | Some (Token.Kwd c2) ->
106*9880d681SAndroid Build Coastguard Worker              (* If BinOp binds less tightly with rhs than the operator after
107*9880d681SAndroid Build Coastguard Worker               * rhs, let the pending operator take rhs as its lhs. *)
108*9880d681SAndroid Build Coastguard Worker              let next_prec = precedence c2 in
109*9880d681SAndroid Build Coastguard Worker              if token_prec < next_prec
110*9880d681SAndroid Build Coastguard Worker              then parse_bin_rhs (token_prec + 1) rhs stream
111*9880d681SAndroid Build Coastguard Worker              else rhs
112*9880d681SAndroid Build Coastguard Worker          | _ -> rhs
113*9880d681SAndroid Build Coastguard Worker        in
114*9880d681SAndroid Build Coastguard Worker
115*9880d681SAndroid Build Coastguard Worker        (* Merge lhs/rhs. *)
116*9880d681SAndroid Build Coastguard Worker        let lhs = Ast.Binary (c, lhs, rhs) in
117*9880d681SAndroid Build Coastguard Worker        parse_bin_rhs expr_prec lhs stream
118*9880d681SAndroid Build Coastguard Worker      end
119*9880d681SAndroid Build Coastguard Worker  | _ -> lhs
120*9880d681SAndroid Build Coastguard Worker
121*9880d681SAndroid Build Coastguard Worker(* expression
122*9880d681SAndroid Build Coastguard Worker *   ::= primary binoprhs *)
123*9880d681SAndroid Build Coastguard Workerand parse_expr = parser
124*9880d681SAndroid Build Coastguard Worker  | [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream
125*9880d681SAndroid Build Coastguard Worker
126*9880d681SAndroid Build Coastguard Worker(* prototype
127*9880d681SAndroid Build Coastguard Worker *   ::= id '(' id* ')' *)
128*9880d681SAndroid Build Coastguard Workerlet parse_prototype =
129*9880d681SAndroid Build Coastguard Worker  let rec parse_args accumulator = parser
130*9880d681SAndroid Build Coastguard Worker    | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
131*9880d681SAndroid Build Coastguard Worker    | [< >] -> accumulator
132*9880d681SAndroid Build Coastguard Worker  in
133*9880d681SAndroid Build Coastguard Worker
134*9880d681SAndroid Build Coastguard Worker  parser
135*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Ident id;
136*9880d681SAndroid Build Coastguard Worker       'Token.Kwd '(' ?? "expected '(' in prototype";
137*9880d681SAndroid Build Coastguard Worker       args=parse_args [];
138*9880d681SAndroid Build Coastguard Worker       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
139*9880d681SAndroid Build Coastguard Worker      (* success. *)
140*9880d681SAndroid Build Coastguard Worker      Ast.Prototype (id, Array.of_list (List.rev args))
141*9880d681SAndroid Build Coastguard Worker
142*9880d681SAndroid Build Coastguard Worker  | [< >] ->
143*9880d681SAndroid Build Coastguard Worker      raise (Stream.Error "expected function name in prototype")
144*9880d681SAndroid Build Coastguard Worker
145*9880d681SAndroid Build Coastguard Worker(* definition ::= 'def' prototype expression *)
146*9880d681SAndroid Build Coastguard Workerlet parse_definition = parser
147*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
148*9880d681SAndroid Build Coastguard Worker      Ast.Function (p, e)
149*9880d681SAndroid Build Coastguard Worker
150*9880d681SAndroid Build Coastguard Worker(* toplevelexpr ::= expression *)
151*9880d681SAndroid Build Coastguard Workerlet parse_toplevel = parser
152*9880d681SAndroid Build Coastguard Worker  | [< e=parse_expr >] ->
153*9880d681SAndroid Build Coastguard Worker      (* Make an anonymous proto. *)
154*9880d681SAndroid Build Coastguard Worker      Ast.Function (Ast.Prototype ("", [||]), e)
155*9880d681SAndroid Build Coastguard Worker
156*9880d681SAndroid Build Coastguard Worker(*  external ::= 'extern' prototype *)
157*9880d681SAndroid Build Coastguard Workerlet parse_extern = parser
158*9880d681SAndroid Build Coastguard Worker  | [< 'Token.Extern; e=parse_prototype >] -> e
159