Advertisement
DanFloyd

Functional Language Interpreter

Aug 9th, 2015
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 7.54 KB | None | 0 0
  1. (* This is the core of a simple functional language interpreter *)
  2.  
  3. (* shortcuts *)
  4. let _zerodiv = "division by zero"
  5. let _nonexpr = "not expressible value"
  6. let _nonbool = "non boolean parameters"
  7. let _nonint  = "non integer parameters"
  8. let _nonop   = "unrecognized operation"
  9. let _nonfun  = "non function parameter"
  10. let _nomatch = "expression not matched"
  11.  
  12. (* definizione di ambiente *)
  13. (*
  14.   tipo polimorfo di funzione che prende come parametro un identificatore, concretizzato da una stringa, e restituisce
  15.   il valore di tipo 't ad esso associato
  16. *)
  17. type 't _env = string -> 't
  18.  
  19. (* definizione di pattern *)
  20. (*
  21.   tipo polimorfo per la costruzione di pattern, come vedremo verrà caratterizzato sotto in modo da poterlo sfruttare
  22.   per la creazione di pattern su espressioni
  23. *)
  24. type 't _pattern =
  25.   | Default of 't
  26.   | Elem    of 't * 't
  27.   | Comp    of 't * 't * 't _pattern
  28.  
  29. (* espressioni: la sintassi astratta del linguaggio, tutto ciò che l'utente può esprimere *)
  30. type exp =
  31.   | Ide    of string
  32.   | EInt   of int
  33.   | EBool  of bool
  34.   | And    of exp * exp
  35.   | Or     of exp * exp
  36.   | Not    of exp
  37.   | Op     of string * exp * exp
  38.   | If     of exp * exp * exp
  39.   | Let    of string * exp * exp
  40.   | FunDec of string * exp             (* dichiarazione di funzione con singolo parametro *)
  41.   | FunApp of exp * exp                (* applicazione di funzione con singolo parametro *)
  42.   | Try    of string * exp * exp _pattern;; (* costrutto try ide with exp in pattern *)
  43.  
  44. (*
  45.   N.B. per estendere il linguaggio con la possibilità di dichiarare ed applicare funzioni con più di un parametro
  46.   si potrebbe utilizzare una lista di string * exp ed una funzione helper per gestire quest'ultima
  47. *)
  48.  
  49. (* valori denotabili ed esprimibili *)
  50. type value =
  51.   | Int  of int
  52.   | Bool of bool
  53.   | Fun  of string * exp * value _env (* parametro, espressione ed ambiente associato al momento della definizione *)
  54. (*| Fun  of string * exp                 dynamic scoping: parametro ed espressione, l'ambiente associato è quello
  55.                                          presente al momento dell'applicazione
  56. *)
  57.   | Novalue;;
  58.  
  59. (*
  60.   per semplicità viene caratterizzato il tipo polimorfo _env con il tipo value, adesso identifica un tipo di funzione
  61.   che prende come parametro un identificatore, concretizzato da una stringa, e restituisce il valore esprimibile
  62.   associato a tale identificatore (se esiste), altrimenti, come vedremo, restituirà Novalue
  63.  *)
  64. type env = value _env;;
  65.  
  66. (* per semplicità viene caratterizzato il tipo polimorfo pattern con il tipo exp *)
  67. type pattern = exp _pattern;;
  68.  
  69. (*
  70.   N.B. gli identificatori sono rappresentati direttamente da stringhe, senza definire ulteriormente il tipo
  71.   ide = string per questioni di leggibilità
  72. *)
  73.  
  74. (*
  75.   ambiente vuoto, qualsiasi sia l'identificatore inserito come parametro la funzione restituisce Novalue, ovvero
  76.   l'assenza di binding
  77. *)
  78. let empty_env = fun (ide:string) -> Novalue
  79.  
  80. (*
  81.   estensione di ambiente, la funzione restituisce l'espressione se l'identificatore passato come parametro coincide
  82.   con il binding corrente, altrimenti affida la ricerca del binding corretto alla funzione en che identificatore
  83.   l'ambiente precedente, risalendo se necessario tutti gli ambienti esterni e terminando con l'ambiente vuoto nell
  84.   caso non si identifichi nessun binding corretto
  85. *)
  86. let extend_env (en:env) (id:string) (va:value) = fun (ide:string) -> if ide = id then va else en ide
  87.  
  88. (* OPERATORI LOGICI *)
  89.  
  90. (* 'and' logico *)
  91. let _and (a,b) = match (a,b) with
  92.   | (Bool(x),Bool(y)) -> Bool(x && y)
  93.   | _                 -> failwith _nonbool
  94.  
  95. (* 'or' logico *)
  96. let _or (a,b) = match (a,b) with
  97.   | (Bool(x),Bool(y)) -> Bool(x || y)
  98.   | _                 -> failwith _nonbool
  99.  
  100. (* negazione logica *)
  101. let _not a = match a with
  102.   | Bool(x) -> if x = true then Bool(false) else Bool(true)
  103.   | _       -> failwith _nonbool
  104.  
  105. (* OPERATORI SU INTERI *)
  106.  
  107. (* somma tra interi *)
  108. let _add (a,b) = match (a,b) with
  109.   | (Int(x),Int(y)) -> Int(x + y)
  110.   | _               -> failwith _nonint
  111.  
  112. (* sottrazione tra interi *)
  113. let _sub (a,b) = match (a,b) with
  114.   | (Int(x),Int(y)) -> Int(x - y)
  115.   | _               -> failwith _nonint
  116.  
  117. (* moltiplicazione tra interi *)
  118. let _mul (a,b) = match (a,b) with
  119.   | (Int(x),Int(y)) -> Int(x * y)
  120.   | _               -> failwith _nonint
  121.  
  122. (* divisione intera *)
  123. let _div (a,b) = match (a,b) with
  124.   | (Int(x),Int(y)) -> if y = 0 then failwith _zerodiv else Int(x / y)
  125.   | _               -> failwith _nonint
  126.  
  127. (* OPERATORI DI CONFRONTO *)
  128.  
  129. (* uguaglianza, operatore polimorfo *)
  130. let _equ (a,b) = match (a,b) with
  131.   | (Int(x),Int(y))   -> if x = y then Bool(true) else Bool(false)
  132.   | (Bool(x),Bool(y)) -> if x = y then Bool(true) else Bool(false)
  133.   | _                 -> failwith _nonexpr
  134.  
  135. (* maggiore o uguale, operatore su interi *)
  136. let _geq (a,b) = match (a,b) with
  137.   | (Int(x),Int(y)) -> if x >= y then Bool(true) else Bool(false)
  138.   | _               -> failwith _nonint
  139.  
  140. (* maggiore, operatore su interi *)
  141. let _gre (a,b) = match (a,b) with
  142.   | (Int(x),Int(y)) -> if x > y then Bool(true) else Bool(false)
  143.   | _               -> failwith _nonint
  144.  
  145. (* minore o uguale, operatore su interi *)
  146. let _leq (a,b) = match (a,b) with
  147.   | (Int(x),Int(y)) -> if x <= y then Bool(true) else Bool(false)
  148.   | _               -> failwith _nonint
  149.  
  150. (* minore o uguale, operatore su interi *)
  151. let _les (a,b) = match (a,b) with
  152.   | (Int(x),Int(y)) -> if x < y then Bool(true) else Bool(false)
  153.   | _               -> failwith _nonint
  154.  
  155. (* valutazione di espressioni -> restituisce un valore esprimibile *)
  156. (* ex è l'espressione da valutare, mentre en è l'ambiente in cui valutarla *)
  157. let rec eval (ex:exp) (en:env) = match ex with
  158.   | Ide(i)        -> en i
  159.   | EInt(v)       -> Int(v)
  160.   | EBool(v)      -> Bool(v)
  161.   | And(e1,e2)    -> _and((eval e1 en),(eval e2 en))
  162.   | Or(e1,e2)     -> _or((eval e1 en),(eval e2 en))
  163.   | Not(e1)       -> _not((eval e1 en))
  164.   | Op(op,e1,e2)  -> (match op with
  165.     | "+"  -> _add((eval e1 en),(eval e2 en))
  166.     | "-"  -> _sub((eval e1 en),(eval e2 en))
  167.     | "*"  -> _mul((eval e1 en),(eval e2 en))
  168.     | "/"  -> _div((eval e1 en),(eval e2 en))
  169.     | "="  -> _equ((eval e1 en),(eval e2 en))
  170.     | ">=" -> _geq((eval e1 en),(eval e2 en))
  171.     | ">"  -> _gre((eval e1 en),(eval e2 en))
  172.     | "<=" -> _leq((eval e1 en),(eval e2 en))
  173.     | "<"  -> _les((eval e1 en),(eval e2 en))
  174.     | _    -> failwith _nonop)
  175.   | If(g,e1,e2)   -> (if(eval g en = Bool(true)) then eval e1 en else eval e2 en) (* segue la regola esterna *)
  176.   | Let(id,e1,e2) -> let new_en = extend_env en id (eval e1 en) in eval e2 new_en
  177.   | FunDec(p,b)   -> Fun(p,b,en)
  178. (*| FunDec(p,b)   -> Fun(p,b)                               dynamic scoping *)
  179.   | FunApp(e1,e2) -> _exe((eval e1 en),(eval e2 en))
  180. (*| FunApp(e1,e2) -> _exed((eval e1 en),(eval e2 en),en)    dynamic scoping *)
  181.   | Try(id,e,pat) -> let new_en = extend_env en id (eval e en) in _try(new_en,pat)
  182.  
  183. (* function executor *)
  184. and _exe (f,par) = match f with
  185.   | Fun(p,b,efun) -> let new_en = extend_env efun p par in eval b new_en
  186.   | _              -> failwith _nonfun
  187.  
  188. (* pattern matcher *)
  189. and _try (en,pat) = match pat with
  190.   | Default(e)    -> eval e en
  191.   | Elem(e1,e2)   -> if eval e1 en = Bool(true) then eval e2 en else failwith _nomatch
  192.   | Comp(e1,e2,p) -> if eval e1 en = Bool(true) then eval e2 en else _try (en,p)
  193.  
  194. (* Funcion executor for dynamic scoping
  195.  
  196. and _exed (f,par,en) = match f with
  197.   | Fun(p,b) -> let new_en = extend_env en p par in eval b new_en
  198.   | _        -> failwith _nonfun
  199. *)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement