ruco-cpp 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +17 -0
  3. data/bin/console +14 -0
  4. data/bin/ruco +30 -0
  5. data/bin/setup +7 -0
  6. data/data/ruco/Parser.frame +359 -0
  7. data/data/ruco/Scanner.frame +896 -0
  8. data/data/ruco/picojson/Changes +14 -0
  9. data/data/ruco/picojson/LICENSE +25 -0
  10. data/data/ruco/picojson/Makefile +8 -0
  11. data/data/ruco/picojson/README.mkdn +183 -0
  12. data/data/ruco/picojson/examples/github-issues.cc +110 -0
  13. data/data/ruco/picojson/examples/iostream.cc +70 -0
  14. data/data/ruco/picojson/examples/streaming.cc +76 -0
  15. data/data/ruco/picojson/picojson.h +1299 -0
  16. data/ext/cocor/Action.cpp +81 -0
  17. data/ext/cocor/Action.h +59 -0
  18. data/ext/cocor/ArrayList.cpp +79 -0
  19. data/ext/cocor/ArrayList.h +52 -0
  20. data/ext/cocor/BitArray.cpp +156 -0
  21. data/ext/cocor/BitArray.h +68 -0
  22. data/ext/cocor/CharClass.cpp +42 -0
  23. data/ext/cocor/CharClass.h +48 -0
  24. data/ext/cocor/CharSet.cpp +166 -0
  25. data/ext/cocor/CharSet.h +68 -0
  26. data/ext/cocor/Coco.atg +528 -0
  27. data/ext/cocor/Coco.cpp +173 -0
  28. data/ext/cocor/Comment.cpp +45 -0
  29. data/ext/cocor/Comment.h +51 -0
  30. data/ext/cocor/Copyright.frame +27 -0
  31. data/ext/cocor/DFA.cpp +865 -0
  32. data/ext/cocor/DFA.h +132 -0
  33. data/ext/cocor/Generator.cpp +182 -0
  34. data/ext/cocor/Generator.h +61 -0
  35. data/ext/cocor/Graph.h +59 -0
  36. data/ext/cocor/HashTable.cpp +115 -0
  37. data/ext/cocor/HashTable.h +84 -0
  38. data/ext/cocor/Makefile +11 -0
  39. data/ext/cocor/Melted.cpp +39 -0
  40. data/ext/cocor/Melted.h +51 -0
  41. data/ext/cocor/Node.cpp +69 -0
  42. data/ext/cocor/Node.h +86 -0
  43. data/ext/cocor/Parser.cpp +925 -0
  44. data/ext/cocor/Parser.frame +326 -0
  45. data/ext/cocor/Parser.h +153 -0
  46. data/ext/cocor/ParserGen.cpp +486 -0
  47. data/ext/cocor/ParserGen.h +99 -0
  48. data/ext/cocor/Position.cpp +37 -0
  49. data/ext/cocor/Position.h +46 -0
  50. data/ext/cocor/README.md +12 -0
  51. data/ext/cocor/Scanner.cpp +833 -0
  52. data/ext/cocor/Scanner.frame +897 -0
  53. data/ext/cocor/Scanner.h +291 -0
  54. data/ext/cocor/Sets.h +84 -0
  55. data/ext/cocor/SortedList.cpp +141 -0
  56. data/ext/cocor/SortedList.h +68 -0
  57. data/ext/cocor/State.cpp +77 -0
  58. data/ext/cocor/State.h +55 -0
  59. data/ext/cocor/StringBuilder.cpp +88 -0
  60. data/ext/cocor/StringBuilder.h +29 -0
  61. data/ext/cocor/Symbol.cpp +61 -0
  62. data/ext/cocor/Symbol.h +70 -0
  63. data/ext/cocor/Tab.cpp +1248 -0
  64. data/ext/cocor/Tab.h +245 -0
  65. data/ext/cocor/Target.cpp +41 -0
  66. data/ext/cocor/Target.h +48 -0
  67. data/ext/cocor/build.bat +3 -0
  68. data/ext/cocor/build.sh +4 -0
  69. data/ext/cocor/coc.bat +1 -0
  70. data/ext/cocor/coc.sh +2 -0
  71. data/ext/cocor/cocor_ruby_ext.cpp +124 -0
  72. data/ext/cocor/cygBuild.bat +1 -0
  73. data/ext/cocor/extconf.rb +5 -0
  74. data/ext/cocor/mingwbuild.bat +2 -0
  75. data/ext/cocor/mkmf.log +57 -0
  76. data/ext/cocor/zipsources.bat +1 -0
  77. data/lib/cocor.rb +14 -0
  78. data/lib/ruco/version.rb +3 -0
  79. data/lib/ruco.rb +728 -0
  80. 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
+