Expand macro instructions in the parser.

This commit is contained in:
Benjamin Canou 2016-09-09 18:44:30 +02:00
parent 7044576b3f
commit 18d33ff6ca
2 changed files with 103 additions and 4 deletions

View File

@ -239,8 +239,6 @@ let float_literal =
['0'-'9'] ['0'-'9' '_']* ['0'-'9'] ['0'-'9' '_']*
('.' ['0'-'9' '_']* )? ('.' ['0'-'9' '_']* )?
(['e' 'E'] ['+' '-']? ['0'-'9'] ['0'-'9' '_']*)? (['e' 'E'] ['+' '-']? ['0'-'9'] ['0'-'9' '_']*)?
let cadr =
['c' 'C'] ['a' 'A' 'd' 'D']+ ['r' 'R']
rule indent_tokens st nl = parse rule indent_tokens st nl = parse

View File

@ -23,6 +23,107 @@
open Script_located_ir open Script_located_ir
let expand_caddadr loc str =
let len = String.length str in
if len > 3
&& String.get str 0 = 'c'
&& String.get str (len - 1) = 'r' then
let rec parse i acc =
if i = 0 then
Some (Seq (loc, acc))
else
match String.get str i with
| 'a' -> parse (i - 1) (Prim (loc, "car", []) :: acc)
| 'd' -> parse (i - 1) (Prim (loc, "cdr", []) :: acc)
| _ -> None in
parse (len - 2) []
else
None
exception Not_a_roman
let decimal_of_roman roman =
(* http://rosettacode.org/wiki/Roman_numerals/Decode#OCaml *)
let arabic = ref 0 in
let lastval = ref 0 in
for i = (String.length roman) - 1 downto 0 do
let n =
match roman.[i] with
| 'm' -> 1000
| 'd' -> 500
| 'c' -> 100
| 'l' -> 50
| 'x' -> 10
| 'v' -> 5
| 'i' -> 1
| _ -> raise Not_a_roman
in
if Compare.Int.(n < !lastval)
then arabic := !arabic - n
else arabic := !arabic + n;
lastval := n
done;
!arabic
let expand_dxiiivp loc str arg =
let len = String.length str in
if len > 3
&& String.get str 0 = 'd'
&& String.get str (len - 1) = 'p' then
try
let depth = decimal_of_roman (String.sub str 1 (len - 2)) in
let rec make i =
if i = 0 then
arg
else
let sub = make (i - 1) in
Prim (loc, "dip", [ sub ]) in
Some (make depth)
with Not_a_roman -> None
else None
exception Not_a_pair
let expand_paaiair loc str =
let len = String.length str in
if len > 4
&& String.get str 0 = 'p'
&& String.get str (len - 1) = 'r' then
try
let rec parse i acc =
if String.get str i = 'i'
&& String.get str (i - 1) = 'a' then
parse (i - 2) (Prim (loc, "pair", []) :: acc)
else if String.get str i = 'a' then
match acc with
| [] ->
raise Not_a_pair
| acc :: accs ->
parse (i - 1) (Prim (loc, "dip", [ acc ]) :: accs)
else
raise Not_a_pair in
Some (Seq (loc, parse (len - 2) []))
with Not_a_pair -> None
else
None
let expand = function
| Prim (loc, name, [ arg ]) as original ->
begin match expand_dxiiivp loc name arg with
| None -> original
| Some rewritten -> rewritten
end
| Prim (loc, name, []) as original ->
begin match expand_paaiair loc name with
| None ->
begin match expand_caddadr loc name with
| None -> original
| Some rewritten -> rewritten
end
| Some rewritten -> rewritten
end
| original -> original
let apply node arg = let apply node arg =
match node with match node with
| Prim (loc, n, args) -> Prim (loc, n, args @ [arg]) | Prim (loc, n, args) -> Prim (loc, n, args @ [arg])
@ -53,11 +154,11 @@ nodes:
| n1 = node NEWLINE n2 = nodes { n1 :: n2 } | n1 = node NEWLINE n2 = nodes { n1 :: n2 }
node: node:
| node = line_node { node } | node = line_node { expand node }
| line_node error | line_node error
(* Un seul elt par bloc de '(' ... ')' (pas de NEWLINE ou de ';' *) (* Un seul elt par bloc de '(' ... ')' (pas de NEWLINE ou de ';' *)
{ raise (Sequence_in_parens (pos $startpos $endpos)) } { raise (Sequence_in_parens (pos $startpos $endpos)) }
| node = line_node INDENT nodes = nodes DEDENT { apply_seq node nodes } | node = line_node INDENT nodes = nodes DEDENT { expand (apply_seq node nodes) }
line_node: line_node:
| n1 = line_node n2 = line_node %prec apply { apply n1 n2 } | n1 = line_node n2 = line_node %prec apply { apply n1 n2 }