waxeye 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +21 -0
- data/README +116 -0
- data/lib/waxeye.rb +328 -0
- metadata +55 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Waxeye Parser Generator
|
2
|
+
www.waxeye.org
|
3
|
+
Copyright (C) 2008 Orlando D. A. R. Hill
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
10
|
+
so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
============================================
|
3
|
+
| Waxeye Parser Generator |
|
4
|
+
| v 0.4.0 |
|
5
|
+
| www.waxeye.org |
|
6
|
+
| Copyright (C) 2008 Orlando D. A. R. Hill |
|
7
|
+
============================================
|
8
|
+
|
9
|
+
|
10
|
+
What is Waxeye?
|
11
|
+
===============
|
12
|
+
|
13
|
+
Waxeye makes language development easy and fun. With Waxeye, you can rapidly
|
14
|
+
explore ideas for the syntax of your language.
|
15
|
+
|
16
|
+
Whether you are creating a full programming language, a domain-specific
|
17
|
+
language or just a simple data format, Waxeye will get you there faster.
|
18
|
+
|
19
|
+
|
20
|
+
Features
|
21
|
+
========
|
22
|
+
|
23
|
+
* Scanner-less Parsing
|
24
|
+
|
25
|
+
* Language Independent, Reusable Grammars
|
26
|
+
|
27
|
+
* Modular, Composable Grammars
|
28
|
+
|
29
|
+
* Grammar Testing
|
30
|
+
|
31
|
+
* Automatic AST Generation
|
32
|
+
|
33
|
+
* Choice of Programming Language
|
34
|
+
- Java
|
35
|
+
- Ruby
|
36
|
+
- Scheme
|
37
|
+
|
38
|
+
|
39
|
+
User Manual
|
40
|
+
===========
|
41
|
+
|
42
|
+
Waxeye's user manual is in 'docs/manual.html' and 'docs/manual.pdf'.
|
43
|
+
The latest version is also online at http://waxeye.org/manual.html.
|
44
|
+
|
45
|
+
|
46
|
+
Installation
|
47
|
+
============
|
48
|
+
|
49
|
+
Unix, OSX:
|
50
|
+
1. Extract the files of the distribution.
|
51
|
+
|
52
|
+
2. Copy the 'waxeye' directory to where you wish to install it.
|
53
|
+
|
54
|
+
3. Add the 'bin/waxeye' binary to your search path. e.g. If you have '~/bin' in
|
55
|
+
your PATH and installed waxeye to '/usr/local/waxeye' then you might do the
|
56
|
+
following. ln -s /usr/local/waxeye/bin/waxeye ~/bin/
|
57
|
+
|
58
|
+
|
59
|
+
Windows:
|
60
|
+
1. Extract the files of the distribution.
|
61
|
+
|
62
|
+
2. Copy the 'waxeye' directory to where you wish to install it.
|
63
|
+
|
64
|
+
|
65
|
+
Building
|
66
|
+
========
|
67
|
+
|
68
|
+
1. Install MzScheme v372; either with DrScheme or alone.
|
69
|
+
http://download.plt-scheme.org
|
70
|
+
|
71
|
+
2. Install Waxeye's backend for PLT Scheme.
|
72
|
+
Unix, OSX:
|
73
|
+
sudo ln -s /usr/local/waxeye/src/scheme/waxeye /usr/local/plt/lib/plt/collects/
|
74
|
+
|
75
|
+
Windows:
|
76
|
+
Copy the dir 'src/scheme/waxeye' into your PLT-Scheme collections directory.
|
77
|
+
|
78
|
+
3. Build Waxeye
|
79
|
+
Unix, OSX:
|
80
|
+
./build/unix
|
81
|
+
|
82
|
+
Windows:
|
83
|
+
TODO: Translate 'build/unix' to a Windows equivalent.
|
84
|
+
|
85
|
+
|
86
|
+
Running
|
87
|
+
=======
|
88
|
+
|
89
|
+
Unix, OSX:
|
90
|
+
Use 'waxeye'.
|
91
|
+
|
92
|
+
Windows:
|
93
|
+
Use a command prompt to run `waxeye.exe`.
|
94
|
+
|
95
|
+
|
96
|
+
License
|
97
|
+
=======
|
98
|
+
|
99
|
+
MIT/X11 - All files (except the user manual) are under the permissive MIT/X11
|
100
|
+
license.
|
101
|
+
|
102
|
+
GNU FDL - Waxeye's user manual is under the GNU Free Documentation License.
|
103
|
+
This includes all files in the 'doc/book' directory, 'doc/manual.html' and
|
104
|
+
'doc/manual.pdf'.
|
105
|
+
|
106
|
+
|
107
|
+
Support
|
108
|
+
=======
|
109
|
+
|
110
|
+
Feel free to contact me, if you are having trouble or want to give feedback.
|
111
|
+
|
112
|
+
Either email me directly:
|
113
|
+
orlandodarhill at Gmail.com
|
114
|
+
|
115
|
+
Or signup and post on the mailing list:
|
116
|
+
https://lists.sourceforge.net/lists/listinfo/waxeye-users
|
data/lib/waxeye.rb
ADDED
@@ -0,0 +1,328 @@
|
|
1
|
+
# Waxeye Parser Generator
|
2
|
+
# www.waxeye.org
|
3
|
+
# Copyright (C) 2008 Orlando D. A. R. Hill
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
# this software and associated documentation files (the "Software"), to deal in
|
7
|
+
# the Software without restriction, including without limitation the rights to
|
8
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
9
|
+
# of the Software, and to permit persons to whom the Software is furnished to do
|
10
|
+
# so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
|
24
|
+
module Waxeye
|
25
|
+
|
26
|
+
class Edge
|
27
|
+
attr_reader :trans, :state, :voided
|
28
|
+
def initialize(trans, state, voided)
|
29
|
+
@trans = trans
|
30
|
+
@state = state
|
31
|
+
@voided = voided
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class State
|
36
|
+
attr_reader :edges, :match
|
37
|
+
def initialize(edges, match)
|
38
|
+
@edges = edges
|
39
|
+
@match = match
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Automaton
|
44
|
+
attr_reader :type, :states, :voided
|
45
|
+
def initialize(type, states, voided)
|
46
|
+
@type = type
|
47
|
+
@states = states
|
48
|
+
@voided = voided
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class ParseError
|
53
|
+
attr_reader :pos, :line, :col
|
54
|
+
def initialize(pos, line, col)
|
55
|
+
@pos = pos
|
56
|
+
@line = line
|
57
|
+
@col = col
|
58
|
+
end
|
59
|
+
|
60
|
+
def display()
|
61
|
+
print "parse error at pos=#{pos}, line=#{line}, col=#{col}\n"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class AST
|
66
|
+
attr_reader :type, :children, :pos
|
67
|
+
def initialize(type, children, pos)
|
68
|
+
@type = type
|
69
|
+
@children = children
|
70
|
+
@pos = pos
|
71
|
+
end
|
72
|
+
|
73
|
+
def display_sexpr()
|
74
|
+
display_sexpr_iter(self)
|
75
|
+
print "\n"
|
76
|
+
end
|
77
|
+
|
78
|
+
def display()
|
79
|
+
display_iter(self, [0])
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def display_sexpr_iter(ast)
|
84
|
+
print '('
|
85
|
+
print ast.type
|
86
|
+
ast.children.each do |a|
|
87
|
+
print " "
|
88
|
+
if a.is_a?(Waxeye::AST)
|
89
|
+
display_sexpr_iter(a)
|
90
|
+
else
|
91
|
+
print a
|
92
|
+
end
|
93
|
+
end
|
94
|
+
print ')'
|
95
|
+
end
|
96
|
+
|
97
|
+
def display_iter(ast, indent)
|
98
|
+
(indent[0] - 1).times {|| print ' ' }
|
99
|
+
print '-> ' if indent[0] > 0
|
100
|
+
print ast.type, "\n"
|
101
|
+
indent[0] = indent[0] + 1
|
102
|
+
ast.children.each do |a|
|
103
|
+
if a.is_a?(Waxeye::AST)
|
104
|
+
display_iter(a, indent)
|
105
|
+
else
|
106
|
+
(indent[0] - 1).times {|| print ' ' }
|
107
|
+
print '| ' if indent[0] > 0
|
108
|
+
print a, "\n"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
indent[0] = indent[0] - 1
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class WaxeyeParser
|
116
|
+
def initialize(start, eof_check, line_counting, tab_width, automata)
|
117
|
+
@start = start
|
118
|
+
@eof_check = eof_check
|
119
|
+
@line_counting = line_counting
|
120
|
+
@tab_width = tab_width
|
121
|
+
@automata = automata
|
122
|
+
end
|
123
|
+
|
124
|
+
def parse(input)
|
125
|
+
InnerParser.new(@start, @eof_check, @line_counting, @tab_width, @automata, input).parse()
|
126
|
+
end
|
127
|
+
|
128
|
+
class InnerParser
|
129
|
+
def initialize(start, eof_check, line_counting, tab_width, automata, input)
|
130
|
+
@start = start
|
131
|
+
@eof_check = eof_check
|
132
|
+
@line_counting = line_counting
|
133
|
+
@tab_width = tab_width
|
134
|
+
@automata = automata
|
135
|
+
@states_stack = []
|
136
|
+
@cache = {}
|
137
|
+
@input = input
|
138
|
+
@input_len = input.length
|
139
|
+
@input_pos = 0
|
140
|
+
@line = 0
|
141
|
+
@column = 0
|
142
|
+
@last_cr = false
|
143
|
+
@error_pos = 0
|
144
|
+
@error_line = 0
|
145
|
+
@error_col = 0
|
146
|
+
end
|
147
|
+
|
148
|
+
def parse()
|
149
|
+
eof_check(match_automaton(@start))
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def match_automaton(index)
|
155
|
+
start_pos = @input_pos
|
156
|
+
key = [index, start_pos]
|
157
|
+
|
158
|
+
if (@cache.has_key?(key))
|
159
|
+
cachedItem = @cache.fetch(key)
|
160
|
+
restore_pos(cachedItem[1], cachedItem[2], cachedItem[3], cachedItem[4])
|
161
|
+
return cachedItem[0]
|
162
|
+
end
|
163
|
+
|
164
|
+
start_line = @line
|
165
|
+
start_col = @column
|
166
|
+
start_cr = @last_cr
|
167
|
+
automaton = @automata[index]
|
168
|
+
type = automaton.type
|
169
|
+
states = automaton.states
|
170
|
+
voided = automaton.voided
|
171
|
+
|
172
|
+
@states_stack.push(states)
|
173
|
+
res = match_state(0)
|
174
|
+
@states_stack.pop()
|
175
|
+
|
176
|
+
value = if type == :_and
|
177
|
+
restore_pos(start_pos, start_line, start_col, start_cr)
|
178
|
+
not not res
|
179
|
+
elsif type == :_not
|
180
|
+
restore_pos(start_pos, start_line, start_col, start_cr)
|
181
|
+
if res
|
182
|
+
update_error()
|
183
|
+
false
|
184
|
+
else
|
185
|
+
true
|
186
|
+
end
|
187
|
+
else
|
188
|
+
if res
|
189
|
+
(voided ? true : AST.new(type, res, :pos))
|
190
|
+
else
|
191
|
+
update_error()
|
192
|
+
false
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
@cache.store(key, [value, @input_pos, @line, @column, @last_cr])
|
197
|
+
return value
|
198
|
+
end
|
199
|
+
|
200
|
+
def match_state(index)
|
201
|
+
state = @states_stack.last[index]
|
202
|
+
res = match_edges(state.edges)
|
203
|
+
res ? res : (state.match and [])
|
204
|
+
end
|
205
|
+
|
206
|
+
def match_edges(edges)
|
207
|
+
if edges == []
|
208
|
+
false
|
209
|
+
else
|
210
|
+
res = match_edge(edges[0])
|
211
|
+
res ? res : match_edges(edges[1..-1])
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def match_edge(edge)
|
216
|
+
start_pos = @input_pos
|
217
|
+
start_line = @line
|
218
|
+
start_col = @column
|
219
|
+
start_cr = @last_cr
|
220
|
+
t = edge.trans
|
221
|
+
res = if t == :_wild
|
222
|
+
@input_pos < @input_len ? mv() : (update_error(); false)
|
223
|
+
elsif t.is_a?(String)
|
224
|
+
@input_pos < @input_len and t[0] == @input[@input_pos] ? mv() : (update_error(); false)
|
225
|
+
elsif t.is_a?(Array)
|
226
|
+
@input_pos < @input_len and within_set?(t, @input[@input_pos]) ? mv() : (update_error(); false)
|
227
|
+
elsif t.is_a?(Integer)
|
228
|
+
match_automaton(t)
|
229
|
+
else
|
230
|
+
false
|
231
|
+
end
|
232
|
+
|
233
|
+
if res
|
234
|
+
tran_res = match_state(edge.state)
|
235
|
+
if tran_res
|
236
|
+
if edge.voided or res == true
|
237
|
+
tran_res
|
238
|
+
else
|
239
|
+
[res] + tran_res
|
240
|
+
end
|
241
|
+
else
|
242
|
+
restore_pos(start_pos, start_line, start_col, start_cr)
|
243
|
+
false
|
244
|
+
end
|
245
|
+
else
|
246
|
+
false
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def restore_pos(pos, line, col, cr)
|
251
|
+
@input_pos = pos
|
252
|
+
@line = line
|
253
|
+
@column = col
|
254
|
+
@last_cr = cr
|
255
|
+
end
|
256
|
+
|
257
|
+
def update_error()
|
258
|
+
if @error_pos < @input_pos
|
259
|
+
@error_pos = @input_pos
|
260
|
+
@error_line = @line
|
261
|
+
@error_col = @column
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def mv()
|
266
|
+
ch = @input[@input_pos].chr()
|
267
|
+
@input_pos = @input_pos + 1
|
268
|
+
|
269
|
+
if ch == '\r'
|
270
|
+
@line = @line + 1
|
271
|
+
@column = 0
|
272
|
+
@last_cr = true
|
273
|
+
else
|
274
|
+
if ch == '\n'
|
275
|
+
if not @last_cr
|
276
|
+
@line = @line + 1
|
277
|
+
@column = 0
|
278
|
+
end
|
279
|
+
else
|
280
|
+
@column = @column + 1
|
281
|
+
end
|
282
|
+
@last_cr = false
|
283
|
+
end
|
284
|
+
|
285
|
+
return ch
|
286
|
+
end
|
287
|
+
|
288
|
+
def eof_check(res)
|
289
|
+
if res
|
290
|
+
if @eof_check and @input_pos < @input_len
|
291
|
+
# Create a parse error - Not all input consumed
|
292
|
+
ParseError.new(@error_pos, @error_line, @error_col)
|
293
|
+
else
|
294
|
+
res
|
295
|
+
end
|
296
|
+
else
|
297
|
+
# Create a parse error
|
298
|
+
ParseError.new(@error_pos, @error_line, @error_col)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def within_set?(set, c)
|
303
|
+
if set == []
|
304
|
+
false
|
305
|
+
else
|
306
|
+
aa = set[0]
|
307
|
+
|
308
|
+
if aa.is_a?(String)
|
309
|
+
if aa[0] == c
|
310
|
+
true
|
311
|
+
else
|
312
|
+
aa[0] < c ? within_set?(set[1..-1], c) : false
|
313
|
+
end
|
314
|
+
else
|
315
|
+
# If not a String then must be a range
|
316
|
+
if aa.include?(c)
|
317
|
+
true
|
318
|
+
else
|
319
|
+
aa.max < c ? within_set?(set[1..-1], c) : false
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: waxeye
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Orlando D. A. R. Hill
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-08-07 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: orlandodarhill Gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- LICENSE
|
27
|
+
- lib/waxeye.rb
|
28
|
+
has_rdoc: false
|
29
|
+
homepage: http://waxeye.org
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: "0"
|
40
|
+
version:
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
requirements: []
|
48
|
+
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 1.1.1
|
51
|
+
signing_key:
|
52
|
+
specification_version: 2
|
53
|
+
summary: The Ruby runtime for Waxeye parsers
|
54
|
+
test_files: []
|
55
|
+
|