ruco-cpp 0.2.1
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.
- checksums.yaml +7 -0
- data/Rakefile +17 -0
- data/bin/console +14 -0
- data/bin/ruco +30 -0
- data/bin/setup +7 -0
- data/data/ruco/Parser.frame +359 -0
- data/data/ruco/Scanner.frame +896 -0
- data/data/ruco/picojson/Changes +14 -0
- data/data/ruco/picojson/LICENSE +25 -0
- data/data/ruco/picojson/Makefile +8 -0
- data/data/ruco/picojson/README.mkdn +183 -0
- data/data/ruco/picojson/examples/github-issues.cc +110 -0
- data/data/ruco/picojson/examples/iostream.cc +70 -0
- data/data/ruco/picojson/examples/streaming.cc +76 -0
- data/data/ruco/picojson/picojson.h +1299 -0
- data/ext/cocor/Action.cpp +81 -0
- data/ext/cocor/Action.h +59 -0
- data/ext/cocor/ArrayList.cpp +79 -0
- data/ext/cocor/ArrayList.h +52 -0
- data/ext/cocor/BitArray.cpp +156 -0
- data/ext/cocor/BitArray.h +68 -0
- data/ext/cocor/CharClass.cpp +42 -0
- data/ext/cocor/CharClass.h +48 -0
- data/ext/cocor/CharSet.cpp +166 -0
- data/ext/cocor/CharSet.h +68 -0
- data/ext/cocor/Coco.atg +528 -0
- data/ext/cocor/Coco.cpp +173 -0
- data/ext/cocor/Comment.cpp +45 -0
- data/ext/cocor/Comment.h +51 -0
- data/ext/cocor/Copyright.frame +27 -0
- data/ext/cocor/DFA.cpp +865 -0
- data/ext/cocor/DFA.h +132 -0
- data/ext/cocor/Generator.cpp +182 -0
- data/ext/cocor/Generator.h +61 -0
- data/ext/cocor/Graph.h +59 -0
- data/ext/cocor/HashTable.cpp +115 -0
- data/ext/cocor/HashTable.h +84 -0
- data/ext/cocor/Makefile +11 -0
- data/ext/cocor/Melted.cpp +39 -0
- data/ext/cocor/Melted.h +51 -0
- data/ext/cocor/Node.cpp +69 -0
- data/ext/cocor/Node.h +86 -0
- data/ext/cocor/Parser.cpp +925 -0
- data/ext/cocor/Parser.frame +326 -0
- data/ext/cocor/Parser.h +153 -0
- data/ext/cocor/ParserGen.cpp +486 -0
- data/ext/cocor/ParserGen.h +99 -0
- data/ext/cocor/Position.cpp +37 -0
- data/ext/cocor/Position.h +46 -0
- data/ext/cocor/README.md +12 -0
- data/ext/cocor/Scanner.cpp +833 -0
- data/ext/cocor/Scanner.frame +897 -0
- data/ext/cocor/Scanner.h +291 -0
- data/ext/cocor/Sets.h +84 -0
- data/ext/cocor/SortedList.cpp +141 -0
- data/ext/cocor/SortedList.h +68 -0
- data/ext/cocor/State.cpp +77 -0
- data/ext/cocor/State.h +55 -0
- data/ext/cocor/StringBuilder.cpp +88 -0
- data/ext/cocor/StringBuilder.h +29 -0
- data/ext/cocor/Symbol.cpp +61 -0
- data/ext/cocor/Symbol.h +70 -0
- data/ext/cocor/Tab.cpp +1248 -0
- data/ext/cocor/Tab.h +245 -0
- data/ext/cocor/Target.cpp +41 -0
- data/ext/cocor/Target.h +48 -0
- data/ext/cocor/build.bat +3 -0
- data/ext/cocor/build.sh +4 -0
- data/ext/cocor/coc.bat +1 -0
- data/ext/cocor/coc.sh +2 -0
- data/ext/cocor/cocor_ruby_ext.cpp +124 -0
- data/ext/cocor/cygBuild.bat +1 -0
- data/ext/cocor/extconf.rb +5 -0
- data/ext/cocor/mingwbuild.bat +2 -0
- data/ext/cocor/mkmf.log +57 -0
- data/ext/cocor/zipsources.bat +1 -0
- data/lib/cocor.rb +14 -0
- data/lib/ruco/version.rb +3 -0
- data/lib/ruco.rb +728 -0
- metadata +195 -0
data/lib/ruco.rb
ADDED
@@ -0,0 +1,728 @@
|
|
1
|
+
require "ruco/version"
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'tsort'
|
4
|
+
|
5
|
+
module Ruco
|
6
|
+
|
7
|
+
class TsortableHash < Hash
|
8
|
+
include TSort
|
9
|
+
alias tsort_each_node each_key
|
10
|
+
def tsort_each_child(node, &block)
|
11
|
+
fetch(node).each(&block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class LitString
|
16
|
+
attr_accessor :str
|
17
|
+
def initialize(str, prodset)
|
18
|
+
@str = str
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate(indent=0)
|
22
|
+
"#{("\t"*indent)}\"#{str}\""
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Identifier
|
27
|
+
attr_accessor :name, :prodset
|
28
|
+
def initialize(name)
|
29
|
+
@name = name
|
30
|
+
@prodset = prodset
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate(indent=0)
|
34
|
+
|
35
|
+
code = "production->#{name.downcase} = #{name.downcase};"
|
36
|
+
if @prodset[name][:count] > 1
|
37
|
+
code = "production->#{name.downcase.pluralize}.push_back(#{name.downcase});"
|
38
|
+
end
|
39
|
+
"#{("\t"*indent)}#{name}<#{name.downcase}> (. #{code} .)"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Token
|
44
|
+
attr_accessor :name
|
45
|
+
def initialize(name, prodset)
|
46
|
+
@name = name
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate(indent=0)
|
50
|
+
"#{("\t"*indent)}#{name} (. production->content = t->val; .)"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Sync
|
55
|
+
def generate(indent=0)
|
56
|
+
"#{("\t"*indent)}SYNC"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Variation < Identifier
|
61
|
+
|
62
|
+
def generate(indent=0)
|
63
|
+
code = "production = #{name.downcase};"
|
64
|
+
"#{("\t"*indent)}#{name}<#{name.downcase}> (. #{code} .)"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Group
|
69
|
+
def initialize(type=:normal, prodset={})
|
70
|
+
@type = type
|
71
|
+
@prodset = prodset
|
72
|
+
@stuff = []
|
73
|
+
end
|
74
|
+
|
75
|
+
def Object.const_missing(m)
|
76
|
+
return Identifier.new("#{m}")
|
77
|
+
end
|
78
|
+
|
79
|
+
def convert_thing(thing)
|
80
|
+
if thing.is_a? String
|
81
|
+
return LitString.new(thing, @prodset)
|
82
|
+
end
|
83
|
+
|
84
|
+
if thing.is_a? Identifier or thing.is_a? Variation
|
85
|
+
|
86
|
+
thing.prodset = @prodset
|
87
|
+
|
88
|
+
if !@prodset[thing.name]
|
89
|
+
@prodset[thing.name] = {count: 0, type: :id}
|
90
|
+
end
|
91
|
+
@prodset[thing.name][:count] += 1
|
92
|
+
@prodset[thing.name][:count] += 1 unless @type == :normal or @type == :either
|
93
|
+
end
|
94
|
+
|
95
|
+
if thing.is_a? Token
|
96
|
+
if !@prodset[thing.name]
|
97
|
+
@prodset[thing.name] = {count: 0, type: :token}
|
98
|
+
end
|
99
|
+
@prodset[thing.name][:count] += 1
|
100
|
+
@prodset[thing.name][:count] += 1 unless @type == :normal or @type == :either
|
101
|
+
end
|
102
|
+
|
103
|
+
return thing
|
104
|
+
end
|
105
|
+
|
106
|
+
def sync
|
107
|
+
@stuff << Sync.new
|
108
|
+
end
|
109
|
+
|
110
|
+
def one(thing)
|
111
|
+
thing = convert_thing(thing)
|
112
|
+
@stuff << thing
|
113
|
+
end
|
114
|
+
|
115
|
+
def either(*args)
|
116
|
+
g = Group.new :either, @prodset
|
117
|
+
|
118
|
+
g.instance_eval do
|
119
|
+
args.each do |x|
|
120
|
+
one x
|
121
|
+
end
|
122
|
+
end
|
123
|
+
one g
|
124
|
+
end
|
125
|
+
|
126
|
+
def maybe(thing)
|
127
|
+
g = Group.new :maybe, @prodset
|
128
|
+
g.instance_eval do
|
129
|
+
one thing
|
130
|
+
end
|
131
|
+
one g
|
132
|
+
end
|
133
|
+
|
134
|
+
def many(thing, options=nil)
|
135
|
+
one thing
|
136
|
+
maybemany thing, options
|
137
|
+
end
|
138
|
+
|
139
|
+
def maybemany(thing, options=nil)
|
140
|
+
g = Group.new :multiple, @prodset
|
141
|
+
g.instance_eval do
|
142
|
+
if options[:separator].is_a? String
|
143
|
+
one options[:separator]
|
144
|
+
else
|
145
|
+
puts "Separator needs to be a simple string"
|
146
|
+
end if options
|
147
|
+
one thing
|
148
|
+
end
|
149
|
+
one g
|
150
|
+
end
|
151
|
+
|
152
|
+
def group(&block)
|
153
|
+
g = Group.new :normal, @prodset
|
154
|
+
g.instance_eval(&block)
|
155
|
+
g
|
156
|
+
end
|
157
|
+
|
158
|
+
def generate(indent=0)
|
159
|
+
|
160
|
+
result = []
|
161
|
+
|
162
|
+
@stuff.each do |x|
|
163
|
+
result << "#{x.generate(indent+1)}"
|
164
|
+
end
|
165
|
+
|
166
|
+
openbrace = "("
|
167
|
+
closebrace = ")"
|
168
|
+
divider = ""
|
169
|
+
|
170
|
+
openbrace = "[" if @type == :maybe
|
171
|
+
closebrace = "]" if @type == :maybe
|
172
|
+
|
173
|
+
openbrace = "{" if @type == :multiple
|
174
|
+
closebrace = "}" if @type == :multiple
|
175
|
+
|
176
|
+
|
177
|
+
divider = "|" if @type == :either
|
178
|
+
|
179
|
+
("\t"*indent) + openbrace + "\n" + result.join("#{divider}\n") + "\n" + ("\t"*indent) + closebrace
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
class Production < Group
|
185
|
+
|
186
|
+
attr_accessor :prodset, :prodtype
|
187
|
+
|
188
|
+
def initialize(name, prodtype=:normal)
|
189
|
+
|
190
|
+
@prodtype = prodtype
|
191
|
+
@name = name
|
192
|
+
super()
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
class Ruco < Production
|
198
|
+
def initialize(grammar_name, &block)
|
199
|
+
@name = grammar_name
|
200
|
+
super(grammar_name)
|
201
|
+
@productions = {grammar_name => self}
|
202
|
+
instance_eval(&block)
|
203
|
+
end
|
204
|
+
|
205
|
+
def grammar(name, &block)
|
206
|
+
p = Production.new(name, &block)
|
207
|
+
p.instance_eval(&block)
|
208
|
+
@productions[name] = p
|
209
|
+
end
|
210
|
+
|
211
|
+
def variation(name, *args)
|
212
|
+
p = Production.new(name, :variation)
|
213
|
+
p.instance_eval do
|
214
|
+
g = Group.new :either, @prodset
|
215
|
+
g.instance_eval do
|
216
|
+
args.each do |x|
|
217
|
+
if x.is_a? Identifier
|
218
|
+
one Variation.new(x.name)
|
219
|
+
else
|
220
|
+
puts "Variation needs to be a grammar"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
one g
|
225
|
+
end
|
226
|
+
@productions[name] = p
|
227
|
+
end
|
228
|
+
|
229
|
+
def token(name, type)
|
230
|
+
p = Production.new(name)
|
231
|
+
case type
|
232
|
+
when :pascal_case
|
233
|
+
p.instance_eval do
|
234
|
+
one Token.new("pascalcase", @prodset)
|
235
|
+
end
|
236
|
+
when :camel_case
|
237
|
+
p.instance_eval do
|
238
|
+
one Token.new("camelcase", @prodset)
|
239
|
+
end
|
240
|
+
when :hex_integer
|
241
|
+
p.instance_eval do
|
242
|
+
one Token.new("hexinteger", @prodset)
|
243
|
+
end
|
244
|
+
when :integer
|
245
|
+
p.instance_eval do
|
246
|
+
one Token.new("integer", @prodset)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
@productions[name] = p
|
250
|
+
end
|
251
|
+
|
252
|
+
def generate_header()
|
253
|
+
|
254
|
+
classlist = []
|
255
|
+
|
256
|
+
parent_map = {}
|
257
|
+
|
258
|
+
dependency_hash = TsortableHash.new
|
259
|
+
|
260
|
+
@productions.each do |prodname, prod|
|
261
|
+
|
262
|
+
if prod.prodtype == :normal
|
263
|
+
|
264
|
+
prod.prodset.each do |key, prodinfo|
|
265
|
+
|
266
|
+
if prodinfo[:type] == :id
|
267
|
+
if !dependency_hash[prodname]
|
268
|
+
dependency_hash[prodname] = []
|
269
|
+
end
|
270
|
+
dependency_hash[prodname] << "#{key}"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
elsif prod.prodtype == :variation
|
275
|
+
|
276
|
+
prod.prodset.each do |key, prodinfo|
|
277
|
+
|
278
|
+
if prodinfo[:type] == :id
|
279
|
+
if !dependency_hash[key]
|
280
|
+
dependency_hash[key] = []
|
281
|
+
end
|
282
|
+
dependency_hash[key] << "#{prodname}"
|
283
|
+
|
284
|
+
if !parent_map[key]
|
285
|
+
parent_map[key] = []
|
286
|
+
end
|
287
|
+
parent_map[key] << "#{prodname}"
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
# remaining productions
|
298
|
+
@productions.each do |prodname, prod|
|
299
|
+
if !dependency_hash[prodname]
|
300
|
+
dependency_hash[prodname] = []
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
#puts "Dependency Chain:"
|
305
|
+
#p dependency_hash
|
306
|
+
|
307
|
+
dependency_hash.tsort.each do |prodname|
|
308
|
+
|
309
|
+
prod = @productions[prodname]
|
310
|
+
|
311
|
+
|
312
|
+
memberlist = []
|
313
|
+
if prod.prodtype == :normal
|
314
|
+
|
315
|
+
prod.prodset.each do |key, prodinfo|
|
316
|
+
name = "#{key}"
|
317
|
+
|
318
|
+
if prodinfo[:type] == :id
|
319
|
+
|
320
|
+
#puts "#{name} -> #{prodinfo[:count]}"
|
321
|
+
|
322
|
+
if prodinfo[:count] > 1
|
323
|
+
memberlist << "#{name}Array #{name.downcase.pluralize};"
|
324
|
+
else
|
325
|
+
memberlist << "#{name}Ptr #{name.downcase};"
|
326
|
+
end
|
327
|
+
|
328
|
+
elsif prodinfo[:type] == :token
|
329
|
+
|
330
|
+
memberlist << "std::wstring content;"
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
elsif prod.prodtype == :variation
|
336
|
+
|
337
|
+
enumeration_list = []
|
338
|
+
prod.prodset.each do |key, prodinfo|
|
339
|
+
enumeration_list << "\t#{key.upcase}_#{prodname.upcase}"
|
340
|
+
end
|
341
|
+
|
342
|
+
enumerations = enumeration_list.join ",\n"
|
343
|
+
|
344
|
+
|
345
|
+
classlist << <<-TYPE_ENUM_CONTENT
|
346
|
+
enum #{prodname}Type
|
347
|
+
{
|
348
|
+
#{enumerations}
|
349
|
+
};
|
350
|
+
TYPE_ENUM_CONTENT
|
351
|
+
|
352
|
+
memberlist << "virtual #{prodname}Type get_#{prodname.downcase}_type() const = 0;"
|
353
|
+
|
354
|
+
else
|
355
|
+
puts "UNKNOWN PRODUCTION TYPE: #{prod.prodtype}"
|
356
|
+
end
|
357
|
+
|
358
|
+
parent_declaration = ""
|
359
|
+
parent_impl = ""
|
360
|
+
|
361
|
+
if parent_map[prodname]
|
362
|
+
list = parent_map[prodname].map{|x| "public #{x}"}.join ", "
|
363
|
+
parent_declaration = ": #{list}"
|
364
|
+
|
365
|
+
parent_map[prodname].each do |parent|
|
366
|
+
memberlist << <<-PARENTDECL
|
367
|
+
virtual #{parent}Type get_#{parent.downcase}_type() const
|
368
|
+
{
|
369
|
+
return #{prodname.upcase}_#{parent.upcase};
|
370
|
+
}
|
371
|
+
PARENTDECL
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|
375
|
+
|
376
|
+
members = memberlist.map {|x| "\t#{x}"}.join "\n"
|
377
|
+
|
378
|
+
classlist << <<-CLASSCONTENT
|
379
|
+
class #{prodname} #{parent_declaration}
|
380
|
+
{
|
381
|
+
public:
|
382
|
+
#{members}
|
383
|
+
};
|
384
|
+
typedef std::shared_ptr<#{prodname}> #{prodname}Ptr;
|
385
|
+
typedef std::vector<#{prodname}Ptr> #{prodname}Array;
|
386
|
+
CLASSCONTENT
|
387
|
+
end
|
388
|
+
|
389
|
+
classes = classlist.join "\n"
|
390
|
+
|
391
|
+
header = <<-HEADEREND
|
392
|
+
|
393
|
+
#ifndef #{@name.upcase}_HPP
|
394
|
+
#define #{@name.upcase}_HPP
|
395
|
+
|
396
|
+
/*
|
397
|
+
WARNING: This file is generated using ruco. Please modify the .ruco file if you wish to change anything
|
398
|
+
https://github.com/davidsiaw/ruco
|
399
|
+
*/
|
400
|
+
|
401
|
+
#include <string>
|
402
|
+
#include <memory>
|
403
|
+
#include <vector>
|
404
|
+
|
405
|
+
namespace #{@name}
|
406
|
+
{
|
407
|
+
|
408
|
+
#{classes}
|
409
|
+
|
410
|
+
}
|
411
|
+
|
412
|
+
#endif // #{@name.upcase}_HPP
|
413
|
+
|
414
|
+
HEADEREND
|
415
|
+
|
416
|
+
header
|
417
|
+
|
418
|
+
end
|
419
|
+
|
420
|
+
def generate_libhpp()
|
421
|
+
<<-HPPCONTENT
|
422
|
+
|
423
|
+
#ifndef PARSE_#{@name.upcase}_HPP
|
424
|
+
#define PARSE_#{@name.upcase}_HPP
|
425
|
+
|
426
|
+
/*
|
427
|
+
WARNING: This file is generated using ruco. Please modify the .ruco file if you wish to change anything
|
428
|
+
https://github.com/davidsiaw/ruco
|
429
|
+
*/
|
430
|
+
|
431
|
+
#include <iostream>
|
432
|
+
#include <memory>
|
433
|
+
#include <fstream>
|
434
|
+
#include <sstream>
|
435
|
+
#include <string>
|
436
|
+
#include <vector>
|
437
|
+
#include <set>
|
438
|
+
|
439
|
+
#include "Scanner.h"
|
440
|
+
#include "Parser.h"
|
441
|
+
|
442
|
+
#include "picojson.hpp"
|
443
|
+
|
444
|
+
namespace #{@name}
|
445
|
+
{
|
446
|
+
/**
|
447
|
+
* Parses a source file into the data structure of #{@name}
|
448
|
+
*/
|
449
|
+
#{@name}Ptr Parse(std::string sourceFile);
|
450
|
+
|
451
|
+
/**
|
452
|
+
* Transforms the data structure of #{@name} to an abstract syntax tree in JSON format
|
453
|
+
*/
|
454
|
+
picojson::value Jsonify(#{@name}Ptr parseResult);
|
455
|
+
}
|
456
|
+
|
457
|
+
#endif // PARSE_#{@name.upcase}_HPP
|
458
|
+
|
459
|
+
HPPCONTENT
|
460
|
+
end
|
461
|
+
|
462
|
+
def write_jsonify_function(prodname, prod)
|
463
|
+
|
464
|
+
pset = <<-PSETEND
|
465
|
+
object[L"_type"] = picojson::value(L"#{prodname}");
|
466
|
+
PSETEND
|
467
|
+
|
468
|
+
if prod.prodtype == :variation
|
469
|
+
|
470
|
+
switchladder = ""
|
471
|
+
|
472
|
+
prod.prodset.each do |key, prodinfo|
|
473
|
+
|
474
|
+
switchladder += <<-LADDEREND
|
475
|
+
case #{key.upcase}_#{prodname.upcase}:
|
476
|
+
{
|
477
|
+
content = Compile#{key}(std::dynamic_pointer_cast<#{key}>(pointer));
|
478
|
+
break;
|
479
|
+
}
|
480
|
+
LADDEREND
|
481
|
+
|
482
|
+
end
|
483
|
+
|
484
|
+
pset += <<-PSETEND
|
485
|
+
picojson::object content;
|
486
|
+
switch(pointer->get_#{prodname.downcase}_type())
|
487
|
+
{
|
488
|
+
#{switchladder}
|
489
|
+
}
|
490
|
+
|
491
|
+
object[L"_content"] = picojson::value(content);
|
492
|
+
PSETEND
|
493
|
+
|
494
|
+
|
495
|
+
elsif prod.prodtype == :normal
|
496
|
+
|
497
|
+
members_code = ""
|
498
|
+
|
499
|
+
prod.prodset.each do |key, prodinfo|
|
500
|
+
|
501
|
+
members_code += <<-MEMBERCODEEND
|
502
|
+
// #{prodinfo}
|
503
|
+
MEMBERCODEEND
|
504
|
+
|
505
|
+
if prodinfo[:count] == 1
|
506
|
+
|
507
|
+
if prodinfo[:type] == :token
|
508
|
+
|
509
|
+
members_code += <<-PSETEND
|
510
|
+
object[L"_token"] = picojson::value(pointer->content);
|
511
|
+
PSETEND
|
512
|
+
|
513
|
+
elsif prodinfo[:type] == :id
|
514
|
+
members_code += <<-PSETEND
|
515
|
+
|
516
|
+
picojson::object #{key.downcase};
|
517
|
+
|
518
|
+
#{key.downcase} = Compile#{key}(pointer->#{key.downcase});
|
519
|
+
|
520
|
+
object[L"#{key.downcase}"] = picojson::value(#{key.downcase});
|
521
|
+
PSETEND
|
522
|
+
end
|
523
|
+
|
524
|
+
else
|
525
|
+
|
526
|
+
if prodinfo[:type] == :token
|
527
|
+
raise "Unimplemented"
|
528
|
+
|
529
|
+
elsif prodinfo[:type] == :id
|
530
|
+
members_code += <<-PSETEND
|
531
|
+
|
532
|
+
picojson::array #{key.downcase}s;
|
533
|
+
|
534
|
+
for(unsigned i=0; i<pointer->#{key.downcase}s.size(); i++)
|
535
|
+
{
|
536
|
+
#{key.downcase}s.push_back(picojson::value(Compile#{key}(pointer->#{key.downcase}s[i])));
|
537
|
+
}
|
538
|
+
|
539
|
+
object[L"#{key.downcase}s"] = picojson::value(#{key.downcase}s);
|
540
|
+
PSETEND
|
541
|
+
end
|
542
|
+
|
543
|
+
end
|
544
|
+
|
545
|
+
end
|
546
|
+
|
547
|
+
pset += <<-PSETEND
|
548
|
+
|
549
|
+
|
550
|
+
#{members_code}
|
551
|
+
|
552
|
+
|
553
|
+
PSETEND
|
554
|
+
|
555
|
+
end
|
556
|
+
|
557
|
+
funcname = "picojson::object Compile#{prodname}(#{prodname}Ptr pointer)"
|
558
|
+
|
559
|
+
funcdef = <<-FUNCTIONEND
|
560
|
+
#{funcname}
|
561
|
+
{
|
562
|
+
picojson::object object;
|
563
|
+
|
564
|
+
// #{prod.prodtype}
|
565
|
+
#{pset}
|
566
|
+
return object;
|
567
|
+
}
|
568
|
+
|
569
|
+
FUNCTIONEND
|
570
|
+
|
571
|
+
{name: funcname, definition: funcdef}
|
572
|
+
|
573
|
+
end
|
574
|
+
|
575
|
+
def generate_libcpp()
|
576
|
+
|
577
|
+
functions = ""
|
578
|
+
function_declarations = ""
|
579
|
+
|
580
|
+
@productions.each do |prodname, prod|
|
581
|
+
|
582
|
+
f = write_jsonify_function(prodname, prod)
|
583
|
+
functions += f[:definition]
|
584
|
+
function_declarations += <<-FUNCDECLEND
|
585
|
+
#{f[:name]};
|
586
|
+
FUNCDECLEND
|
587
|
+
end
|
588
|
+
|
589
|
+
<<-CPPCONTENT
|
590
|
+
|
591
|
+
#include "parse_#{@name.downcase}.hpp"
|
592
|
+
|
593
|
+
/*
|
594
|
+
WARNING: This file is generated using ruco. Please modify the .ruco file if you wish to change anything
|
595
|
+
https://github.com/davidsiaw/ruco
|
596
|
+
*/
|
597
|
+
|
598
|
+
namespace #{@name}
|
599
|
+
{
|
600
|
+
#{@name}Ptr Parse(std::string sourceFile)
|
601
|
+
{
|
602
|
+
std::shared_ptr<FILE> fp (fopen(sourceFile.c_str(), "r"), fclose);
|
603
|
+
std::shared_ptr<Scanner> scanner (new Scanner(fp.get()));
|
604
|
+
std::shared_ptr<Parser> parser (new Parser(scanner.get()));
|
605
|
+
parser->Parse();
|
606
|
+
|
607
|
+
return parser->#{@name.downcase};
|
608
|
+
}
|
609
|
+
|
610
|
+
#{function_declarations}
|
611
|
+
#{functions}
|
612
|
+
|
613
|
+
picojson::value Jsonify(SerialistPtr parseResult)
|
614
|
+
{
|
615
|
+
return picojson::value(CompileSerialist(parseResult));
|
616
|
+
}
|
617
|
+
|
618
|
+
}
|
619
|
+
|
620
|
+
CPPCONTENT
|
621
|
+
end
|
622
|
+
|
623
|
+
def generate_atg()
|
624
|
+
|
625
|
+
productionlist = []
|
626
|
+
productiondecl = []
|
627
|
+
|
628
|
+
|
629
|
+
@productions.each do |prodname, prod|
|
630
|
+
|
631
|
+
decllist = []
|
632
|
+
|
633
|
+
prod.prodset.each do |key, prodinfo|
|
634
|
+
if prodinfo[:type] == :id
|
635
|
+
decllist << "(. #{key}Ptr #{key.downcase}; .)"
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
declarations = decllist.join "\n"
|
640
|
+
|
641
|
+
attributes = "<#{prodname}Ptr& production>" unless prodname == @name
|
642
|
+
|
643
|
+
constructor = ""
|
644
|
+
|
645
|
+
constructor = "(. production = std::make_shared<class #{prodname}>(); .)" if prod.prodtype == :normal
|
646
|
+
|
647
|
+
production_string = <<-PRODUCTION
|
648
|
+
#{prodname}#{attributes} = #{constructor}
|
649
|
+
#{declarations}
|
650
|
+
#{prod.generate}
|
651
|
+
.
|
652
|
+
PRODUCTION
|
653
|
+
|
654
|
+
production_string.gsub!(/production/, @name.downcase) if prodname == @name
|
655
|
+
|
656
|
+
productionlist << production_string
|
657
|
+
end
|
658
|
+
|
659
|
+
productions = productionlist.join("\n")
|
660
|
+
|
661
|
+
<<-FRAMEEND
|
662
|
+
|
663
|
+
#include <iostream>
|
664
|
+
#include <memory>
|
665
|
+
#include "#{@name}.hpp"
|
666
|
+
|
667
|
+
/*
|
668
|
+
WARNING: This file is generated using ruco. Please modify the .ruco file if you wish to change anything
|
669
|
+
https://github.com/davidsiaw/ruco
|
670
|
+
*/
|
671
|
+
|
672
|
+
COMPILER #{@name}
|
673
|
+
|
674
|
+
#{@name}Ptr #{@name.downcase};
|
675
|
+
|
676
|
+
CHARACTERS
|
677
|
+
bigletter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
|
678
|
+
letter = "abcdefghijklmnopqrstuvwxyz".
|
679
|
+
underscore = "_".
|
680
|
+
digit = "0123456789".
|
681
|
+
cr = '\\r'.
|
682
|
+
lf = '\\n'.
|
683
|
+
tab = '\\t'.
|
684
|
+
stringCh = ANY - '"' - '\\\\' - cr - lf.
|
685
|
+
charCh = ANY - '\\'' - '\\\\' - cr - lf.
|
686
|
+
printable = '\\u0020' .. '\\u007e'.
|
687
|
+
hex = "0123456789abcdef".
|
688
|
+
|
689
|
+
TOKENS
|
690
|
+
pascalcase = bigletter { bigletter | letter | digit }.
|
691
|
+
camelcase = letter { bigletter | letter | digit }.
|
692
|
+
|
693
|
+
integer = digit { digit }.
|
694
|
+
hexinteger = '0' 'x' hex { hex }.
|
695
|
+
|
696
|
+
string = '"' { stringCh | '\\\\' printable } '"'.
|
697
|
+
badString = '"' { stringCh | '\\\\' printable } (cr | lf).
|
698
|
+
char = '\\'' ( charCh | '\\\\' printable { hex } ) '\\''.
|
699
|
+
endOfLine = cr | lf.
|
700
|
+
|
701
|
+
PRAGMAS
|
702
|
+
ddtSym = '$' { digit | letter }.
|
703
|
+
optionSym = '$' letter { letter } '='
|
704
|
+
{ digit | letter
|
705
|
+
| '-' | '.' | ':'
|
706
|
+
}.
|
707
|
+
|
708
|
+
|
709
|
+
COMMENTS FROM "/*" TO "*/" NESTED
|
710
|
+
COMMENTS FROM "//" TO lf
|
711
|
+
|
712
|
+
IGNORE tab + cr + lf
|
713
|
+
|
714
|
+
/*-------------------------------------------------------------------------*/
|
715
|
+
|
716
|
+
PRODUCTIONS
|
717
|
+
|
718
|
+
#{productions}
|
719
|
+
|
720
|
+
|
721
|
+
END #{@name}.
|
722
|
+
|
723
|
+
FRAMEEND
|
724
|
+
|
725
|
+
end
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|