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.
Files changed (4) hide show
  1. data/LICENSE +21 -0
  2. data/README +116 -0
  3. data/lib/waxeye.rb +328 -0
  4. 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
+