Skip to content

Instantly share code, notes, and snippets.

@jdh30
Created April 15, 2017 22:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdh30/de3c157c12396830f439ffbfc7b9ec1a to your computer and use it in GitHub Desktop.
Save jdh30/de3c157c12396830f439ffbfc7b9ec1a to your computer and use it in GitHub Desktop.
FemtoML parser in F# using fslex and fsyacc
{
open Parse
open Lexing
let ident = function
| "let" -> LET
| "rec" -> REC
| "in" -> IN
| "fun" -> FUN
| "if" -> IF
| "then" -> THEN
| "else" -> ELSE
| s -> IDENT s
}
let digit = ['0'-'9']
let alpha = ['a'-'z' 'A'-'Z']+
let ident = alpha+ (alpha | digit)*
rule token = parse
| ['\n' '\r'] { token lexbuf }
| [' ' '\t'] { token lexbuf }
| '=' { EQUAL }
| '+' { PLUS }
| '-' { MINUS }
| '*' { TIMES }
| '/' { DIVIDE }
| '(' { OPEN }
| ')' { CLOSE }
| ";;" { SEMISEMI }
| "->" { RIGHTARROW }
| digit+ { NUM(Math.BigNum.of_string(lexeme lexbuf)) }
| ident { lexeme lexbuf |> ident }
| _ { EOF }
and fsyacc:
%{
open Expr
let applies es =
List.fold1_left (fun h t -> EBinOp(Apply, h, t)) es
%}
%token <string> IDENT
%token <Math.BigNum> NUM
%token EQUAL
%token PLUS MINUS TIMES DIVIDE POWER
%token OPEN CLOSE
%token LET REC IN
%token FUN RIGHTARROW
%token IF THEN ELSE
%token SEMISEMI EOF
%right LET REC IN
%right FUN RIGHTARROW
%right IF THEN ELSE
%left EQUAL
%left PLUS MINUS
%left TIMES DIVIDE
%right POWER
%left prec_uminus
%left prec_apply
%start statement
%type <Expr.statement option> statement
%%
fin:
| SEMISEMI {}
| EOF {}
;
rec_opt: { false }
| REC { true }
;
statement:
| fin { None }
| LET rec_opt IDENT EQUAL expr { Some(SLet($2, $3, $5)) }
| expr fin { Some(SExpr $1) }
;
simple_expr:
| NUM { ENum $1 }
| IDENT { EVar $1 }
| OPEN expr CLOSE { $2 }
;
simple_expr_list:
| simple_expr { [$1] }
| simple_expr simple_expr_list { $1 :: $2 }
;
expr:
| simple_expr { $1 }
| simple_expr simple_expr_list %prec prec_apply { applies ($1::$2) }
| expr EQUAL expr { EBinOp(Equal, $1, $3) }
| expr PLUS expr { $1 + $3 }
| expr MINUS expr { $1 - $3 }
| expr TIMES expr { $1 * $3 }
| expr DIVIDE expr { $1 / $3 }
| FUN IDENT RIGHTARROW expr { EFun($2, $4) }
| IF expr THEN expr ELSE expr { EIf($2, $4, $6) }
| LET rec_opt IDENT EQUAL expr IN expr { ELet($2, $3, $5, $7) }
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment