Add associativity control
This commit is contained in:
		
							parent
							
								
									e859d01683
								
							
						
					
					
						commit
						5aaa261198
					
				
					 3 changed files with 87 additions and 20 deletions
				
			
		
							
								
								
									
										20
									
								
								ast.ml
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								ast.ml
									
										
									
									
									
								
							|  | @ -2,10 +2,12 @@ module Type = struct | |||
|   type t = | ||||
|     | Int | ||||
|     | Float | ||||
|     | String | ||||
| 
 | ||||
|   let to_string = function | ||||
|     | Int -> "int" | ||||
|     | Float -> "float" | ||||
|     | String -> "string" | ||||
| 
 | ||||
|   let merge a b = | ||||
|     match a, b with | ||||
|  | @ -22,16 +24,24 @@ module Value = struct | |||
|   type t = | ||||
|     | Int of int | ||||
|     | Float of float | ||||
|     | String of string | ||||
|     | Nop (* return of system operations *) | ||||
| 
 | ||||
|   let to_string = function | ||||
|     | Int n -> Printf.sprintf "%d" n | ||||
|     | Float n -> Printf.sprintf "%f" n | ||||
|     | Int n -> string_of_int n | ||||
|     | Float n -> string_of_float n | ||||
|     | String s -> s | ||||
|     | Nop -> "nop" | ||||
| 
 | ||||
|   let of_token = function | ||||
|     | Token.Int n -> Int n | ||||
|     | Float n -> Float n | ||||
|     | _ -> invalid_arg "Value.of_token" | ||||
| 
 | ||||
|   let typeof = function | ||||
|     | Int _ -> Type.Int | ||||
|     | Float _ -> Type.Float | ||||
|     | String _ -> Type.String | ||||
|     | Nop -> failwith "Value.typeof" | ||||
| 
 | ||||
|   let promote = function | ||||
|  | @ -92,6 +102,8 @@ type t = | |||
|   | Binop of t * Binop.t * t | ||||
|   | Set_binop_pre of Binop.t * t | ||||
|   | Get_binop_pre of Binop.t | ||||
|   | Set_binop_aso of Binop.t * string | ||||
|   | Get_binop_aso of Binop.t | ||||
| 
 | ||||
| let value v = Value v | ||||
| 
 | ||||
|  | @ -115,5 +127,9 @@ let print ast = | |||
|       pr ")" | ||||
|     | Get_binop_pre op -> | ||||
|       pr "(get_pre %s)" (Binop.to_string op) | ||||
|     | Set_binop_aso (op, aso) -> | ||||
|       pr "(set_assoc %s %s)" (Binop.to_string op) aso | ||||
|     | Get_binop_aso op -> | ||||
|       pr "(get_pre %s)" (Binop.to_string op) | ||||
|   in | ||||
|   aux ast; pr "\n" | ||||
|  |  | |||
							
								
								
									
										7
									
								
								eval.ml
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								eval.ml
									
										
									
									
									
								
							|  | @ -41,5 +41,12 @@ let eval vars ast = | |||
|       Nop | ||||
|     | Get_binop_pre op -> | ||||
|       Int (Hashtbl.find Parser.precedence op) | ||||
|     | Set_binop_aso (op, a) -> | ||||
|       Hashtbl.replace Parser.oper_assoc op @@ Parser.assoc_of_string a; | ||||
|       Nop | ||||
|     | Get_binop_aso op -> | ||||
|       match Hashtbl.find_opt Parser.oper_assoc op with | ||||
|       | None -> String "left" | ||||
|       | Some a -> String (Parser.assoc_to_string a) | ||||
|   in | ||||
|   aux ast | ||||
|  |  | |||
							
								
								
									
										80
									
								
								parser.ml
									
										
									
									
									
								
							
							
						
						
									
										80
									
								
								parser.ml
									
										
									
									
									
								
							|  | @ -33,6 +33,15 @@ type associativity = | |||
|   | Left_to_right | ||||
|   | Right_to_left | ||||
| 
 | ||||
| let assoc_of_string = function | ||||
|   | "left" -> Left_to_right | ||||
|   | "right" -> Right_to_left | ||||
|   | _ -> invalid_arg "assoc_of_string" | ||||
| 
 | ||||
| let assoc_to_string = function | ||||
|   | Left_to_right -> "left" | ||||
|   | Right_to_left -> "right" | ||||
| 
 | ||||
| let oper_assoc = [ | ||||
|   Exp, Right_to_left; | ||||
| ] |> List.to_seq |> Hashtbl.of_seq | ||||
|  | @ -62,6 +71,13 @@ let token_is_operator tok = | |||
| 
 | ||||
| (* common parsers *) | ||||
| 
 | ||||
| let token tok seq = | ||||
|   match seq () with | ||||
|   | Seq.Nil -> expected @@ Token.to_string tok | ||||
|   | Seq.Cons (x, seq) -> | ||||
|     if x = tok then x, seq | ||||
|     else expected @@ Token.to_string tok | ||||
| 
 | ||||
| let idents set seq = | ||||
|   match seq () with | ||||
|   | Seq.Nil -> | ||||
|  | @ -85,23 +101,33 @@ let operator seq = | |||
| 
 | ||||
| (* parser combinators *) | ||||
| 
 | ||||
| let either f g seq = | ||||
|   try f seq with _ -> g seq | ||||
| let oneof fs seq = | ||||
|   let rec aux = function | ||||
|     | [] -> assert false | ||||
|     | [f] -> f seq | ||||
|     | f::fs -> (try f seq with _ -> aux fs) | ||||
|   in | ||||
|   aux fs | ||||
| 
 | ||||
| let (@>) f g seq = | ||||
| let (@>) f g = fun seq -> | ||||
|   let a, seq = f seq in | ||||
|   g a seq | ||||
| 
 | ||||
| (* expr := "level" level_inner | ||||
| (* expr := level | ||||
|  *       | assoc | ||||
|  *       | let | ||||
|  *       | value binop_right | ||||
| *) | ||||
| let rec expr seq = | ||||
|   seq |> either | ||||
|     (ident "level" @> level_inner) | ||||
|     (value @> binop ~-1) | ||||
| let rec expr pre seq = | ||||
|   seq |> oneof [ | ||||
|     level; | ||||
|     assoc; | ||||
|     value @> binop pre; | ||||
|   ] | ||||
| 
 | ||||
| (* level_inner := "get" | "set" [op] *) | ||||
| and level_inner _ seq = | ||||
| (* level := "level" {"get" | "set"} [op] *) | ||||
| and level seq = | ||||
|   let _, seq = ident "level" seq in | ||||
|   let id, seq = idents (S.of_list ["get"; "set"]) seq in | ||||
|   let op, seq = operator seq in | ||||
|   if id = "get" then | ||||
|  | @ -112,7 +138,20 @@ and level_inner _ seq = | |||
|   else | ||||
|     failwith "Parser.level" | ||||
| 
 | ||||
| (* value := int | ( expr ) *) | ||||
| (* assoc := "assoc" {"get" | "set"} [op] *) | ||||
| and assoc seq = | ||||
|   let _, seq = ident "assoc" seq in | ||||
|   let id, seq = idents (S.of_list ["get"; "set"]) seq in | ||||
|   let op, seq = operator seq in | ||||
|   if id = "get" then | ||||
|     Get_binop_aso op, seq | ||||
|   else if id = "set" then | ||||
|     let a, seq = idents (S.of_list ["left"; "right"]) seq in | ||||
|     Set_binop_aso (op, a), seq | ||||
|   else | ||||
|     failwith "Parser.assoc" | ||||
| 
 | ||||
| (* value := int | float | ( expr ) *) | ||||
| and value seq = | ||||
|   match seq () with | ||||
|   | Seq.Nil -> raise End_of_tokens | ||||
|  | @ -120,7 +159,10 @@ and value seq = | |||
|       | Token.Int n -> Value (Int n), seq | ||||
|       | Float n -> Value (Float n), seq | ||||
|       | Ident id -> Var id, seq | ||||
|       | LParen -> expr seq | ||||
|       | LParen -> | ||||
|         let e, seq = expr min_int seq in | ||||
|         let _, seq = token RParen seq in | ||||
|         e, seq | ||||
|       | _ -> unexpected_token x | ||||
|     end | ||||
| 
 | ||||
|  | @ -131,20 +173,22 @@ and binop pre left seq = | |||
|   | Seq.Cons (x, seq) -> begin match x with | ||||
|       | op when token_is_operator op -> | ||||
|         let op = token_to_op op in | ||||
|         let o = precedence_of op in | ||||
|         let op_pre = precedence_of op in | ||||
|         (* op has to be calculated first *) | ||||
|         if o > pre || (op_is_right_to_left op && o = pre) then | ||||
|           let v, seq = value seq in | ||||
|           let right, seq = binop o v seq in | ||||
|         if op_pre > pre | ||||
|         || (op_is_right_to_left op && op_pre = pre) | ||||
|         then | ||||
|           let right, seq = expr op_pre seq in | ||||
|           binop pre (Ast.binop left op right) seq | ||||
|         else | ||||
|           left, Seq.cons x seq | ||||
|       | Token.RParen -> left, seq | ||||
| 
 | ||||
|       | Token.RParen -> left, Seq.cons x seq | ||||
|       | _ -> unexpected_token x | ||||
|     end | ||||
| 
 | ||||
| (* parse tokens *) | ||||
| let parse ts = | ||||
|   let ast, rest = expr ts in | ||||
|   let ast, rest = expr min_int ts in | ||||
|   if rest () <> Seq.Nil then failwith "Parser.parse"; | ||||
|   ast | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue