166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(*===---------------------------------------------------------------------===
266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman * Parser
366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman *===---------------------------------------------------------------------===*)
466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(* binop_precedence - This holds the precedence for each binary operator that is
666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman * defined *)
766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanlet binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(* precedence - Get the precedence of the pending binary operator token. *)
1066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanlet precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
1166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
1266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(* primary
1366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman *   ::= identifier
1466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman *   ::= numberexpr
1566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman *   ::= parenexpr *)
1666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanlet rec parse_primary = parser
1766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  (* numberexpr ::= number *)
1866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< 'Token.Number n >] -> Ast.Number n
1966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
2066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  (* parenexpr ::= '(' expression ')' *)
2166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
2266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
2366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  (* identifierexpr
2466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman   *   ::= identifier
2566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman   *   ::= identifier '(' argumentexpr ')' *)
2666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< 'Token.Ident id; stream >] ->
2766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      let rec parse_args accumulator = parser
2866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        | [< e=parse_expr; stream >] ->
2966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman            begin parser
3066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman              | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
3166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman              | [< >] -> e :: accumulator
3266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman            end stream
3366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        | [< >] -> accumulator
3466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      in
3566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      let rec parse_ident id = parser
3666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (* Call. *)
3766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        | [< 'Token.Kwd '(';
3866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman             args=parse_args [];
3966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman             'Token.Kwd ')' ?? "expected ')'">] ->
4066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman            Ast.Call (id, Array.of_list (List.rev args))
4166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
4266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (* Simple variable ref. *)
4366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        | [< >] -> Ast.Variable id
4466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      in
4566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      parse_ident id stream
4666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
4766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
4866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
4966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(* binoprhs
5066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman *   ::= ('+' primary)* *)
5166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanand parse_bin_rhs expr_prec lhs stream =
5266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  match Stream.peek stream with
5366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  (* If this is a binop, find its precedence. *)
5466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
5566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      let token_prec = precedence c in
5666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
5766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      (* If this is a binop that binds at least as tightly as the current binop,
5866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       * consume it, otherwise we are done. *)
5966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if token_prec < expr_prec then lhs else begin
6066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (* Eat the binop. *)
6166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        Stream.junk stream;
6266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
6366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (* Parse the primary expression after the binary operator. *)
6466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        let rhs = parse_primary stream in
6566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
6666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (* Okay, we know this is a binop. *)
6766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        let rhs =
6866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          match Stream.peek stream with
6966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          | Some (Token.Kwd c2) ->
7066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman              (* If BinOp binds less tightly with rhs than the operator after
7166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman               * rhs, let the pending operator take rhs as its lhs. *)
7266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman              let next_prec = precedence c2 in
7366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman              if token_prec < next_prec
7466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman              then parse_bin_rhs (token_prec + 1) rhs stream
7566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman              else rhs
7666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          | _ -> rhs
7766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        in
7866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
7966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (* Merge lhs/rhs. *)
8066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        let lhs = Ast.Binary (c, lhs, rhs) in
8166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        parse_bin_rhs expr_prec lhs stream
8266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      end
8366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | _ -> lhs
8466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
8566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(* expression
8666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman *   ::= primary binoprhs *)
8766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanand parse_expr = parser
8866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream
8966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
9066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(* prototype
9166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman *   ::= id '(' id* ')' *)
9266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanlet parse_prototype =
9366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  let rec parse_args accumulator = parser
9466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
9566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    | [< >] -> accumulator
9666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  in
9766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
9866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  parser
9966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< 'Token.Ident id;
10066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       'Token.Kwd '(' ?? "expected '(' in prototype";
10166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       args=parse_args [];
10266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
10366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      (* success. *)
10466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      Ast.Prototype (id, Array.of_list (List.rev args))
10566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
10666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< >] ->
10766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      raise (Stream.Error "expected function name in prototype")
10866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
10966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(* definition ::= 'def' prototype expression *)
11066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanlet parse_definition = parser
11166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
11266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      Ast.Function (p, e)
11366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
11466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(* toplevelexpr ::= expression *)
11566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanlet parse_toplevel = parser
11666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< e=parse_expr >] ->
11766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      (* Make an anonymous proto. *)
11866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      Ast.Function (Ast.Prototype ("", [||]), e)
11966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
12066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman(*  external ::= 'extern' prototype *)
12166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanlet parse_extern = parser
12266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  | [< 'Token.Extern; e=parse_prototype >] -> e
123