-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathferrolexParser.sam
154 lines (134 loc) · 3.66 KB
/
ferrolexParser.sam
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
%{
open FerrolexAst
open Ferrolex_var
let compteur = ref 1;;
let hashRules = Hashtbl.create 16;;
%}
%token<string> CODE
%token<string> IDENT
%token<char> CHAR
%token<string> STRING
%token<int> INT
%token AND ANY AS CRD CRG EQUAL EOF EOF_WORD EXCEPT KLEENE LET MINUS SEMICOLON
%token PARD PARG PARSE PLUS RULE VERT
%left VERT
%left concat
%nonassoc KLEENE CHAR PARG STRING CRD PLUS IDENT ANY EOF_WORD
%start file
%%
file<FerrolexAst.file>:
| h = CODE f = file2 {let (l, fe) = f in
{
header = h;
reg_list = l;
bottom = fe
}
}
| f = file2 {let (l, fe) = f in
{
header = "";
reg_list = l;
bottom = fe
}
}
;
file2<((string * FerrolexAst.regexp * string) list) * string>:
| d = def f = file2 {f}
| f = rulesDef {f}
;
def<unit>:
| LET i = IDENT EQUAL r = regexp_raw SEMICOLON {
Hashtbl.add hashRules i r
}
;
rulesDef<((string * FerrolexAst.regexp * string) list) * string>:
| RULE name = IDENT EQUAL PARSE l = rulesMatch fileEnd = rulesDef2 {
let (liste, bottom) = fileEnd in
(name,l, !Ferrolex_var.default_error)::liste, bottom
}
| RULE name = IDENT EQUAL PARSE VERT EOF_WORD c = CODE l = rulesMatch fileEnd = rulesDef2 {
let (liste, bottom) = fileEnd in
(name,l, c)::liste, bottom
}
;
rulesDef2<((string * FerrolexAst.regexp * string) list) * string>:
| AND name = IDENT EQUAL PARSE l = rulesMatch fileEnd = rulesDef2 {
let (liste, bottom) = fileEnd in
(name, l, !Ferrolex_var.default_error)::liste, bottom
}
| AND name = IDENT EQUAL PARSE VERT EOF_WORD c = CODE l = rulesMatch fileEnd = rulesDef2 {
let (liste, bottom) = fileEnd in
(name, l, c)::liste, bottom
}
| f = fileEnd {([], f) }
;
rulesMatch<FerrolexAst.regexp>:
| VERT rc = regexp { rc }
| VERT rc = regexp rest = rulesMatch {
Union (rc, rest)
}
;
regexp_raw<FerrolexAst.regexp>:
| PARG r = regexp_raw PARD {r}
| r1 = regexp_raw VERT r2 = regexp_raw {Union (r1, r2)}
| r = regexp_raw KLEENE {Star r}
| s = STRING {
let l = String.length s in
let sortie = ref Epsilon in
for i = 0 to l-1 do
sortie := Concat (!sortie, new_char s.[i])
done;
!sortie
}
| c = CHAR {
new_char c
}
| r1 = regexp_raw r2 = regexp_raw %prec concat {
Concat (r1, r2)
}
| CRD i1 = iset CRG {
new_chars i1
}
| r = regexp_raw PLUS {
Concat (clean r, Star r)
}
| ANY {
failwith "any not implemented"
}
| i = IDENT {
clean (Hashtbl.find hashRules i);
}
;
iset<FerrolexAst.charSet>:
| EXCEPT s = iset2 { Except (Any , s)}
| s = iset2 EXCEPT s2 = iset2 { Except (s, s2)}
| s = iset2 {s}
;
iset2<FerrolexAst.charSet>:
| i = int_or_char { Single i}
| i1 = int_or_char MINUS i2 = int_or_char { Segment (i1, i2) }
| i = int_or_char s = iset2 { SetUnion (Single i, s)}
| i1 = int_or_char MINUS i2 = int_or_char s = iset2 { SetUnion (Segment (i1, i2), s) }
;
int_or_char<int>:
| c = CHAR { int_of_char c}
| i = INT {i}
;
regexp<FerrolexAst.regexp>:
| r = regexp_raw AS i = IDENT c = CODE {
let num = new_rule () in
Hashtbl.add hashCode num c;
Hashtbl.add hashNames num (Some i);
Concat (r, Character (Rule, num))
}
| r = regexp_raw c = CODE {
let num = new_rule () in
Hashtbl.add hashCode num c;
Hashtbl.add hashNames num None;
Concat (r, Character (Rule, num))
}
;
fileEnd<string>:
| EOF { "" }
| c = CODE EOF { c }
;