-
Notifications
You must be signed in to change notification settings - Fork 1
/
compile-grammar
executable file
·92 lines (76 loc) · 2.24 KB
/
compile-grammar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/perl -w
($gram) = @ARGV;
unless ($gram) {
print <<"EOF";
usage: cgram grammar output
notes: If the output file is "foo", then the ocaml code will be
written into "foo.ml". Make sure the ocaml compiler "ocamlopt"
is present on this system.
EOF
exit 0;
}
unless($gram =~ /^\w*\.gram$/) {
print "input should be a .gram file\n";
exit 1;
}
$gram =~ /^(\w*)\.gram$/;
$out = $1;
open GRAM, "$gram";
open OUT, ">$out.ml";
print OUT <<'EOF';
type phrase = Str of string | Opts of phrase array array
let _ = Random.self_init ()
let randelt a = a.(Random.int (Array.length a))
let rec print phr = match phr with
Str s -> print_string s
| Opts options ->
let parts = randelt options in
Array.iter print parts
(* Grammar definitions *)
EOF
undef $/;
@entries = split(/\s* ^ \s* (?= \S+\s* ::=)/mx, <GRAM>);
close GRAM;
undef $mainphrase; # the goal of the grammar. i.e. the thing we'll be producing
print "parsing grammar '$gram' into '$out.ml'...";
foreach (@entries) {
s/\s* \# .* $//xmg;
if (/\s*(\S*)\s*::=\s*(.*)/s) {
$lhs = $1;
$rhs = $2;
if (!defined ($mainphrase)) {
$mainphrase = $lhs;
print OUT "let rec $lhs = Opts [|\n";
} else {
print OUT "and $lhs = Opts [|\n";
}
@opts = split(/\s*\|\s*/, $rhs);
foreach $opt (@opts) {
print OUT " [|";
$opt =~ s/\s*\n\s*/ /g;
# split just before < and after >
@parts = split(/ (?= <) | (?<= >) /x, $opt);
foreach $part (@parts) {
if ($part =~ /<(.*)>/) { # it's either a grammar part
print OUT " $1;";
} else { # or a string literal
$part =~ s/\\/\\\\/g; # turn \ into \\ for ML printing
$part =~ s/\"/\\\"/g; # likewise for "
print OUT " Str \"$part\";";
}
}
print OUT "|];\n";
}
print OUT "|]\n\n";
} else {
if (/\S/) {
print "********error parsing*******";
close OUT;
exit 1;
}
}
}
print "done.\n";
print OUT "let _ = print $mainphrase\n";
print OUT "let _ = print_string \"\\n\"";
close OUT;