example parsing string to AST
This commit is contained in:
parent
a9e2e3d462
commit
a9fa510483
1
.ocamlformat
Normal file
1
.ocamlformat
Normal file
@ -0,0 +1 @@
|
|||||||
|
margin=100
|
@ -1,4 +1,9 @@
|
|||||||
open Flan
|
open Flan.Parse
|
||||||
|
|
||||||
let () =
|
let () =
|
||||||
Example.print_greeting "mate"
|
let source_str = Flan.Examples.let_bind_int in
|
||||||
|
let lexbuf = Lexing.from_string source_str in
|
||||||
|
Printf.printf "Convert source \"%s\" ->\n" source_str;
|
||||||
|
match parse_program lexbuf with
|
||||||
|
| Ok ast -> print_ast ast
|
||||||
|
| Error msg -> print_endline ("ERROR: \n" ^ msg)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
(lang dune 3.15)
|
(lang dune 3.15)
|
||||||
|
(using menhir 3.0)
|
||||||
|
|
||||||
(name flan)
|
(name flan)
|
||||||
|
|
||||||
@ -19,7 +20,7 @@
|
|||||||
(name flan)
|
(name flan)
|
||||||
(synopsis "A short synopsis")
|
(synopsis "A short synopsis")
|
||||||
(description "A longer description")
|
(description "A longer description")
|
||||||
(depends ocaml dune)
|
(depends ocaml dune menhir)
|
||||||
(tags
|
(tags
|
||||||
(topics "to describe" your project)))
|
(topics "to describe" your project)))
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ bug-reports: "https://github.com/username/reponame/issues"
|
|||||||
depends: [
|
depends: [
|
||||||
"ocaml"
|
"ocaml"
|
||||||
"dune" {>= "3.15"}
|
"dune" {>= "3.15"}
|
||||||
|
"menhir"
|
||||||
"odoc" {with-doc}
|
"odoc" {with-doc}
|
||||||
]
|
]
|
||||||
build: [
|
build: [
|
||||||
|
5
lib/dune
5
lib/dune
@ -1,2 +1,7 @@
|
|||||||
(library
|
(library
|
||||||
(name flan))
|
(name flan))
|
||||||
|
|
||||||
|
(menhir
|
||||||
|
(modules oflan))
|
||||||
|
|
||||||
|
(ocamllex olexer)
|
||||||
|
@ -1 +0,0 @@
|
|||||||
let print_greeting name = print_endline ("G'day, " ^ name)
|
|
4
lib/examples.ml
Normal file
4
lib/examples.ml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
(** Examples of syntax / programs as strings that can be imported and tested *)
|
||||||
|
|
||||||
|
let let_bind_int = "let x = 10"
|
||||||
|
let let_bind_str = "let s = \"hello\" "
|
42
lib/oflan.mly
Normal file
42
lib/oflan.mly
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* Declarations */
|
||||||
|
|
||||||
|
%{
|
||||||
|
open Omniflan.Ast
|
||||||
|
%}
|
||||||
|
|
||||||
|
%token Eof
|
||||||
|
%token Newline
|
||||||
|
%token Let
|
||||||
|
|
||||||
|
%token False
|
||||||
|
%token True
|
||||||
|
%token <string> Ident
|
||||||
|
%token <int> Int
|
||||||
|
%token <float> F32
|
||||||
|
|
||||||
|
%token Equal
|
||||||
|
%token LParen
|
||||||
|
%token RParen
|
||||||
|
|
||||||
|
%start <Omniflan.Ast.program> prog
|
||||||
|
|
||||||
|
%%
|
||||||
|
/* Grammar */
|
||||||
|
|
||||||
|
expr:
|
||||||
|
| i = Int; { Int i }
|
||||||
|
|
||||||
|
stmt:
|
||||||
|
| Let; var_name = Ident; Equal; bound_expr = expr
|
||||||
|
{ Let {
|
||||||
|
loc = $startpos;
|
||||||
|
var_name = var_name;
|
||||||
|
bindee = bound_expr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toplevel_item:
|
||||||
|
| stmt = stmt { Stmt stmt }
|
||||||
|
|
||||||
|
prog:
|
||||||
|
| prog = separated_list(Newline, toplevel_item); Eof { prog }
|
35
lib/olexer.mll
Normal file
35
lib/olexer.mll
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
open Lexing
|
||||||
|
open Oflan
|
||||||
|
|
||||||
|
exception SyntaxError of string
|
||||||
|
|
||||||
|
let next_line lexbuf =
|
||||||
|
let pos = lexbuf.lex_curr_p in
|
||||||
|
lexbuf.lex_curr_p <-
|
||||||
|
{ pos with pos_bol = lexbuf.lex_curr_pos;
|
||||||
|
pos_lnum = pos.pos_lnum + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let digit = ['0'-'9']
|
||||||
|
let digits = digit*
|
||||||
|
let alpha = ['a'-'z' 'A'-'Z']
|
||||||
|
let ident = (alpha) (alpha|digit|'_')* (* regex for identifier *)
|
||||||
|
let whitespace = [' ' '\t']+
|
||||||
|
let newline = '\r' | '\n' | "\r\n"
|
||||||
|
|
||||||
|
let int = digits
|
||||||
|
|
||||||
|
rule read =
|
||||||
|
parse
|
||||||
|
| whitespace { read lexbuf }
|
||||||
|
| newline { next_line lexbuf; read lexbuf }
|
||||||
|
| int { Int (int_of_string (Lexing.lexeme lexbuf))}
|
||||||
|
| "let" { Let }
|
||||||
|
| ident { Ident (Lexing.lexeme lexbuf) }
|
||||||
|
| '=' { Equal }
|
||||||
|
| '(' { LParen }
|
||||||
|
| 'R' { RParen }
|
||||||
|
| eof { Eof }
|
||||||
|
| _ { raise (SyntaxError ("Unexpected char: " ^ Lexing.lexeme lexbuf)) }
|
@ -1,22 +1,29 @@
|
|||||||
|
(*
|
||||||
|
Notes
|
||||||
|
|
||||||
type binary_opt =
|
For now everything will be split into modules inside this one big file while prototyping.
|
||||||
| Add
|
*)
|
||||||
| Subtract
|
|
||||||
| Multiply
|
|
||||||
| Divide
|
|
||||||
|
|
||||||
type expr =
|
module Ast = struct
|
||||||
| Let of { name: string; bindee: expr }
|
type loc = Lexing.position
|
||||||
| Binary of { lhs: expr; rhs: expr; operator: binary_opt }
|
type unary_op = Negate
|
||||||
| IfElse of { condition: expr }
|
type binary_op = Add | Subtract | Multiply | Divide
|
||||||
|
type literal = Int of int
|
||||||
|
|
||||||
type builtin_type =
|
type expr = Int of int
|
||||||
| I32
|
(* | Literal of literal *)
|
||||||
| F32
|
(* | BinaryOp of { lhs: expr; rhs: expr; operator: binary_op } *)
|
||||||
| Bool
|
(* | IfElse of { condition: expr; if_expr: expr; else_expr: expr } *)
|
||||||
| Char
|
|
||||||
|
|
||||||
module Examples = struct
|
and stmt =
|
||||||
let let_bind_int = "let x = 10"
|
| Let of { loc : loc; var_name : string; bindee : expr } (* Let binding "let x = 5" *)
|
||||||
let let_bind_str = "let s = \"hello\" "
|
| FuncDecl (* TODO: arguments *)
|
||||||
|
|
||||||
|
and toplevel_item = Stmt of stmt
|
||||||
|
|
||||||
|
type builtin_type = I32 | F32 | Bool | Char
|
||||||
|
type program = toplevel_item list
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Typer = struct end
|
||||||
|
(** This module helps take an untyped AST and produce a typed AST *)
|
||||||
|
31
lib/parse.ml
Normal file
31
lib/parse.ml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
open Lexing
|
||||||
|
|
||||||
|
exception SyntaxError of string
|
||||||
|
|
||||||
|
(* Prints the line number and character number where the error occurred.*)
|
||||||
|
let print_error_position lexbuf =
|
||||||
|
let pos = lexbuf.lex_curr_p in
|
||||||
|
Printf.sprintf "Line:%d Position:%d" pos.pos_lnum (pos.pos_cnum - pos.pos_bol + 1)
|
||||||
|
|
||||||
|
let parse_program lexbuf =
|
||||||
|
try Ok (Oflan.prog Olexer.read lexbuf) with
|
||||||
|
| SyntaxError msg ->
|
||||||
|
let error_msg = Printf.sprintf "%s: %s\n" (print_error_position lexbuf) msg in
|
||||||
|
Error error_msg
|
||||||
|
| Oflan.Error ->
|
||||||
|
let error_msg = Printf.sprintf "%s: syntax error\n" (print_error_position lexbuf) in
|
||||||
|
Error error_msg
|
||||||
|
|
||||||
|
open Omniflan.Ast
|
||||||
|
|
||||||
|
let string_of_expr expr = match expr with Int i -> "Int " ^ string_of_int i
|
||||||
|
|
||||||
|
let string_of_stmt stmt =
|
||||||
|
match stmt with
|
||||||
|
| Let s -> Printf.sprintf "(%d) Let %s = %s" s.loc.pos_lnum s.var_name (string_of_expr s.bindee)
|
||||||
|
| FuncDecl -> failwith "TODO"
|
||||||
|
|
||||||
|
let print_ast prog =
|
||||||
|
List.iter
|
||||||
|
(fun toplevel -> match toplevel with Stmt stmt -> print_endline (string_of_stmt stmt))
|
||||||
|
prog
|
Loading…
x
Reference in New Issue
Block a user