depager 0.1.9

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 (53) hide show
  1. data/ChangeLog +4 -0
  2. data/Manifest.txt +52 -0
  3. data/README.en +64 -0
  4. data/README.ja +128 -0
  5. data/bin/depager +47 -0
  6. data/data/depager/misc/depager-mode.el +209 -0
  7. data/data/depager/sample/extension/paction.dr +15 -0
  8. data/data/depager/sample/extension/pactiontest.dr +14 -0
  9. data/data/depager/sample/pl0d/pl0ds.dr +334 -0
  10. data/data/depager/sample/pl0d/pl0test.pl0 +34 -0
  11. data/data/depager/sample/sample_calc/calc.action.dr +33 -0
  12. data/data/depager/sample/sample_calc/calc.astdf.dr +54 -0
  13. data/data/depager/sample/sample_calc/calc.astl.action.dr +66 -0
  14. data/data/depager/sample/sample_calc/calc.astl.dr +55 -0
  15. data/data/depager/sample/sample_calc/calc.atree.dr +43 -0
  16. data/data/depager/sample/sample_calc/calc.cst.dr +45 -0
  17. data/data/depager/sample/sample_calc/calc.dr +43 -0
  18. data/data/depager/sample/sample_calc/calc.lex.dr +29 -0
  19. data/data/depager/sample/sample_calc/calc.nvaction.dr +33 -0
  20. data/data/depager/sample/sample_calc/calc_prec.nvaction.dr +31 -0
  21. data/data/depager/sample/slex_test/slextest1.dr +37 -0
  22. data/data/depager/sample/slex_test/slextest2.dr +33 -0
  23. data/lib/depager.rb +608 -0
  24. data/lib/depager/Rakefile +30 -0
  25. data/lib/depager/action.rb +47 -0
  26. data/lib/depager/ast_base.dr +232 -0
  27. data/lib/depager/ast_base.rb +1249 -0
  28. data/lib/depager/astdf.rb +10 -0
  29. data/lib/depager/astl.rb +14 -0
  30. data/lib/depager/atree.dr +55 -0
  31. data/lib/depager/atree.rb +336 -0
  32. data/lib/depager/cst.dr +182 -0
  33. data/lib/depager/cst.rb +625 -0
  34. data/lib/depager/lex.dr +76 -0
  35. data/lib/depager/lex.rb +306 -0
  36. data/lib/depager/lr.rb +604 -0
  37. data/lib/depager/nvaction.rb +21 -0
  38. data/lib/depager/parse_action.rb +24 -0
  39. data/lib/depager/parser.rb +248 -0
  40. data/lib/depager/psrtmpl.rb +33 -0
  41. data/lib/depager/slex.dr +161 -0
  42. data/lib/depager/slex.rb +646 -0
  43. data/lib/depager/srp.rb +50 -0
  44. data/lib/depager/template/astdf.erbs +57 -0
  45. data/lib/depager/template/astl.erbs +57 -0
  46. data/lib/depager/template/extension_lalr_master.erb +51 -0
  47. data/lib/depager/template/extension_lalr_slave.erb +107 -0
  48. data/lib/depager/template/simple.erb +21 -0
  49. data/lib/depager/template/single_lalr_parser.erb +97 -0
  50. data/lib/depager/utils.rb +355 -0
  51. data/lib/depager/version.rb +9 -0
  52. data/setup.rb +1585 -0
  53. metadata +103 -0
@@ -0,0 +1,66 @@
1
+ %class TinyCalc
2
+ %extend Lexer ('depager/lex.rb')
3
+ %extend ASTBuilderLazy ('depager/astl.rb')
4
+ %extend Action ('depager/action.rb')
5
+ %decorate @ASTBuilderLazy
6
+ %decorate @Action
7
+ #%decorate ShiftReducePrinter ('depager/srp.rb')
8
+ %mixin Depager
9
+ %%
10
+
11
+ %LEX{
12
+ /\s+/, /\#.*/, /\n/ { }
13
+ /[1-9][0-9]*/ { yield _Token(:NUM, $&.to_i) }
14
+ /./ { yield _Token($&, $&) }
15
+ %}
16
+
17
+ %AST{
18
+ Node [value] { @value = nil }
19
+ Visitor { }
20
+ add(left, right) { ~value = visit(~left).value + visit(~right).value }
21
+ sub(left, right) { ~value = visit(~left).value - visit(~right).value }
22
+ mul(left, right) { ~value = visit(~left).value * visit(~right).value }
23
+ div(left, right) { ~value = visit(~left).value / visit(~right).value }
24
+ literal(-n) { ~value = ~n.value }
25
+ %}
26
+
27
+ #begin-rule
28
+ expr :
29
+ expr '+' term
30
+ => add(expr, term)
31
+ { val[0] + val[2] }
32
+ | expr '-' term
33
+ => sub(expr, term)
34
+ { val[0] - val[2] }
35
+ | term
36
+ => term
37
+ { val[0] }
38
+ ;
39
+ term :
40
+ term '*' fact
41
+ => mul(term, fact)
42
+ { val[0] * val[2] }
43
+ | term '/' fact
44
+ => div(term, fact)
45
+ { val[0] / val[2] }
46
+ | fact
47
+ => fact
48
+ { val[0] }
49
+ ;
50
+ fact :
51
+ NUM
52
+ => literal(NUM)
53
+ { val[0].value }
54
+ | '(' expr ')'
55
+ => expr
56
+ { val[1].value }
57
+ ;
58
+ #end-rule
59
+ %%
60
+ require 'pp'
61
+ parser = createDecoratedTinyCalc()
62
+ t, r = parser.yyparse(STDIN)
63
+ v = Visitor.new
64
+ pp r
65
+ pp t.accept(v).value
66
+ pp t
@@ -0,0 +1,55 @@
1
+ %class TinyCalc
2
+ %extend Lexer ('depager/lex.rb')
3
+ %extend ASTBuilderLazy ('depager/astl.rb')
4
+ %decorate @ASTBuilderLazy
5
+ #%decorate ShiftReducePrinter ('depager/srp.rb')
6
+ %%
7
+
8
+ %LEX{
9
+ /\s+/, /\#.*/ { }
10
+ /[1-9][0-9]*/ { yield _Token(:NUM, $&.to_i) }
11
+ /./ { yield _Token($&, $&) }
12
+ %}
13
+
14
+ %AST{
15
+ Node [value] { @value = nil }
16
+ Visitor { }
17
+ add(left, right) { ~value = visit(~left).value + visit(~right).value }
18
+ sub(left, right) { ~value = visit(~left).value - visit(~right).value }
19
+ mul(left, right) { ~value = visit(~left).value * visit(~right).value }
20
+ div(left, right) { ~value = visit(~left).value / visit(~right).value }
21
+ literal(-n) { ~value = ~n.value }
22
+ %}
23
+
24
+ #begin-rule
25
+ expr :
26
+ expr '+' term
27
+ => add(expr, term)
28
+ | expr '-' term
29
+ => sub(expr, term)
30
+ | term
31
+ => term
32
+ ;
33
+ term :
34
+ term '*' fact
35
+ => mul(term, fact)
36
+ | term '/' fact
37
+ => div(term, fact)
38
+ | fact
39
+ => fact
40
+ ;
41
+ fact :
42
+ NUM
43
+ => literal(NUM)
44
+ | '(' expr ')'
45
+ => expr
46
+ ;
47
+ #end-rule
48
+ %%
49
+ require 'pp'
50
+ parser = createDecoratedTinyCalc()
51
+ t, = parser.yyparse(STDIN)
52
+ v = Visitor.new
53
+ pp t.accept(v).value
54
+ pp t
55
+
@@ -0,0 +1,43 @@
1
+ %class TinyCalc
2
+ %extend Lexer ('depager/lex.rb')
3
+ %extend ATreeBuilder ('depager/atree.rb')
4
+ %decorate @ATreeBuilder
5
+ #%decorate ShiftReducePrinter ('depager/srp.rb')
6
+ %mixin Depager
7
+ %%
8
+
9
+ %LEX{
10
+ /\s+/, /\#.*/ { }
11
+ /[1-9][0-9]*/ { yield _Token(:NUM, $&.to_i) }
12
+ /./ { yield _Token($&, $&) }
13
+ %}
14
+
15
+ #begin-rule
16
+ expr :
17
+ expr '+' term
18
+ => add(expr, term)
19
+ | expr '-' term
20
+ => sub(expr, term)
21
+ | term
22
+ => term
23
+ ;
24
+ term :
25
+ term '*' fact
26
+ => mul(term, fact)
27
+ | term '/' fact
28
+ => div(term, fact)
29
+ | fact
30
+ => fact
31
+ ;
32
+ fact :
33
+ NUM
34
+ => literal(NUM)
35
+ | '(' expr ')'
36
+ => expr
37
+ ;
38
+ #end-rule
39
+ %%
40
+ require 'pp'
41
+ parser = createDecoratedTinyCalc
42
+ r, = parser.yyparse(STDIN)
43
+ pp r
@@ -0,0 +1,45 @@
1
+ %class TinyCalc
2
+ %extend Lexer ('depager/lex.rb')
3
+ %extend CSTBuilder ('depager/cst.rb')
4
+ %decorate @CSTBuilder
5
+ %%
6
+
7
+ %LEX{
8
+ /\s+/, /\#.*/ { }
9
+ /[1-9][0-9]*/ { yield _Token(:NUM, $&.to_i) }
10
+ /./ { yield _Token($&, $&) }
11
+ %}
12
+
13
+ %CST{
14
+ Node {
15
+ attr_accessor :value
16
+ def initialize
17
+ @value = nil
18
+ end
19
+ }
20
+ %}
21
+
22
+ #begin-rule
23
+ expr :
24
+ expr '+' term { ~value = ~expr.value + ~term.value }
25
+ | expr '-' term { ~value = ~expr.value + ~term.value }
26
+ | term { ~value = ~term.value }
27
+ ;
28
+ term :
29
+ term '*' fact { ~value = ~term.value * ~fact.value }
30
+ | term '/' fact { ~value = ~term.value / ~fact.value }
31
+ | fact { ~value = ~fact.value }
32
+ ;
33
+ fact :
34
+ NUM { ~value = ~num.value }
35
+ | '(' expr ')' { ~value = ~expr }
36
+ ;
37
+ #end-rule
38
+ %%
39
+ require 'pp'
40
+ parser = createDecoratedTinyCalc
41
+ r, = parser.yyparse(STDIN)
42
+ v = Visitor.new
43
+ r.accept(v)
44
+ pp r
45
+ puts r.value
@@ -0,0 +1,43 @@
1
+ %class TinyCalc
2
+ %inner{
3
+ def lex
4
+ until @file.eof?
5
+ @line = @file.gets
6
+ until @line.empty? do
7
+ case @line
8
+ when /\A\s+/, /\A\#.*/, /\A\n/
9
+ #skip blank and comment
10
+ when /\A[0-9]+/
11
+ yield :NUM, $&
12
+ when /\A./
13
+ yield $&, $&
14
+ else
15
+ raise RuntimeError, "must not happen #{line}"
16
+ end
17
+ @line = $'
18
+ end
19
+ end
20
+ yield nil, nil
21
+ end
22
+ %}
23
+ %%
24
+
25
+ #begin-rule
26
+ expr :
27
+ expr '+' term
28
+ | expr '-' term
29
+ | term
30
+ ;
31
+ term :
32
+ term '*' fact
33
+ | term '/' fact
34
+ | fact
35
+ ;
36
+ fact :
37
+ NUM
38
+ | '(' expr ')'
39
+ ;
40
+ #end-rule
41
+ %%
42
+ parser = TinyCalc.new()
43
+ parser.yyparse(STDIN)
@@ -0,0 +1,29 @@
1
+ %class TinyCalc
2
+ %extend Lexer ('depager/lex.rb')
3
+ %%
4
+
5
+ %LEX{
6
+ /\s+/, /\#.*/, /\n/ { }
7
+ /[1-9][0-9]*/ { yield :NUM, $&.to_i }
8
+ /./ { yield $&, $& }
9
+ %}
10
+
11
+ #begin-rule
12
+ expr :
13
+ expr '+' term
14
+ | expr '-' term
15
+ | term
16
+ ;
17
+ term :
18
+ term '*' fact
19
+ | term '/' fact
20
+ | fact
21
+ ;
22
+ fact :
23
+ NUM
24
+ | '(' expr ')'
25
+ ;
26
+ #end-rule
27
+ %%
28
+ parser = TinyCalc.new()
29
+ parser.yyparse(STDIN)
@@ -0,0 +1,33 @@
1
+ %class TinyCalc
2
+ %extend Lexer ('depager/lex.rb')
3
+ %extend NVAction ('depager/nvaction.rb')
4
+ %decorate @NVAction
5
+ #%decorate ShiftReducePrinter ('depager/srp.rb')
6
+ %%
7
+
8
+ %LEX{
9
+ /\s+/, /\#.*/ { }
10
+ /[1-9][0-9]*/ { yield _Token(:NUM, $&.to_i) }
11
+ /./ { yield _Token($&, $&) }
12
+ %}
13
+
14
+ #begin-rule
15
+ expr :
16
+ expr '+' term { _expr + _term }
17
+ | expr '-' term { _expr - _term }
18
+ | term { _term }
19
+ ;
20
+ term :
21
+ term '*' fact { _term * _fact }
22
+ | term '/' fact { _term / _fact }
23
+ | fact { _fact }
24
+ ;
25
+ fact :
26
+ NUM { _NUM.value }
27
+ | '(' expr ')' { _expr }
28
+ ;
29
+ #end-rule
30
+ %%
31
+ parser = createDecoratedTinyCalc
32
+ r, = parser.yyparse(STDIN)
33
+ puts r
@@ -0,0 +1,31 @@
1
+ %class TinyCalc
2
+ %extend Lexer ('depager/lex.rb')
3
+ %extend NVAction ('depager/nvaction.rb')
4
+ %decorate @NVAction
5
+ #%decorate ShiftReducePrinter ('depager/srp.rb')
6
+ %prec{
7
+ left '*' '/'
8
+ left '+' '-'
9
+ %}
10
+ %%
11
+
12
+ %LEX{
13
+ /\s+/, /\#.*/ { }
14
+ /[1-9][0-9]*/ { yield _Token(:NUM, $&.to_i) }
15
+ /./ { yield _Token($&, $&) }
16
+ %}
17
+
18
+ #begin-rule
19
+ expr :
20
+ expr-left '+' expr-right { _left + _right }
21
+ | expr-left '-' expr-right { _left - _right }
22
+ | expr-left '*' expr-right { _left * _right }
23
+ | expr-left '/' expr-right { _left / _right }
24
+ | '(' expr ')' { _expr }
25
+ | NUM { _NUM.value }
26
+ ;
27
+ #end-rule
28
+ %%
29
+ parser = createDecoratedTinyCalc
30
+ r, = parser.yyparse(STDIN)
31
+ puts r
@@ -0,0 +1,37 @@
1
+ %class StatefulLexerTest1
2
+ %extend StatefulLexer ('depager/slex.rb')
3
+ %extend NVAction ('depager/nvaction.rb')
4
+ %decorate @NVAction
5
+ %decorate @StatefulLexer
6
+ #%decorate ShiftReducePrinter ('depager/srp.rb')
7
+ %%
8
+ %LEX{
9
+ <START>
10
+ /\s+/ { }
11
+ /\/(([^\/\\]+|\\.)*)\// { yield _Token(:REGEXP, $&) }
12
+ /./ { yield _Token($&, $&) }
13
+ <OPMODE : START>
14
+ '\/' { yield _Token($&, $&) }
15
+ %}
16
+
17
+ #begin-rule
18
+ expr:
19
+ expr '/' [>:START] fact
20
+ | fact
21
+ ;
22
+ fact:
23
+ REGEXP [>:OPMODE]
24
+ { warn "REGEXP: #{_REGEXP.value}" }
25
+ ;
26
+ #end-rule
27
+ %%
28
+ =begin
29
+ stmt:
30
+ TYPEDEF [>:TNMODE] TYPENAME ';' [>:START]
31
+ { warn 'TYPEDEF:'+val[2] }
32
+ | ID ';'
33
+ { warn 'ID:'+val[0] }
34
+ ;
35
+ =end
36
+ p = createDecoratedStatefulLexerTest1
37
+ p.yyparse(STDIN)
@@ -0,0 +1,33 @@
1
+ %class StatefulLexerTest2
2
+ %extend StatefulLexer ('depager/slex.rb')
3
+ %extend Action ('depager/action.rb')
4
+ %decorate @Action
5
+ %decorate @StatefulLexer
6
+ #%decorate ShiftReducePrinter ('depager/srp.rb')
7
+ %%
8
+ %LEX{
9
+ <START>
10
+ /[ \t]+/ { }
11
+ /\n/ { yield :EOL, $& }
12
+ /\w+/ { yield :ID, $& }
13
+ /./ { yield $&, $& }
14
+ <LCONT : START>
15
+ /\r?\n/ { }
16
+ %}
17
+
18
+ #begin-rule
19
+ stmts:
20
+ | stmts expr EOL
21
+ { warn "<EOL>:#{@lexstate}" }
22
+ ;
23
+ expr:
24
+ expr '+' [>:LCONT] fact
25
+ | fact
26
+ ;
27
+ fact:
28
+ ID [>:START]
29
+ ;
30
+ #end-rule
31
+ %%
32
+ p = createDecoratedStatefulLexerTest2
33
+ p.yyparse(STDIN)
@@ -0,0 +1,608 @@
1
+ require 'erb'
2
+ require "depager/lr.rb"
3
+ require "depager/parser.rb"
4
+ require "depager/utils.rb"
5
+
6
+ module Depager
7
+ Tmpldir = "#{File.dirname(__FILE__)}/depager/template"
8
+ #
9
+ # file manager
10
+ #
11
+ class FileManager
12
+ def initialize f=nil
13
+ @file = f
14
+ end
15
+ def file= f
16
+ @file = f
17
+ end
18
+ def eof?
19
+ @file.eof?
20
+ end
21
+ # get file name
22
+ def fname
23
+ File.basename @file.path
24
+ end
25
+ # get file path
26
+ def path
27
+ @file.path
28
+ end
29
+ # get current line no
30
+ def lineno
31
+ @file.lineno
32
+ end
33
+
34
+ # get next line
35
+ def getline
36
+ @file.gets
37
+ end
38
+ alias gets getline
39
+ end
40
+
41
+ #
42
+ # = declaration part parser
43
+ #
44
+ class DeclParser
45
+ attr_accessor :target_name, :g_parser, :generator
46
+ def initialize
47
+ end
48
+ def parse(file, fname=nil)
49
+ @files = FileManager.new(file)
50
+ @target_name = nil
51
+
52
+ parse_decl
53
+ end
54
+ def files
55
+ @files
56
+ end
57
+ alias file files
58
+ def parse_decl
59
+ until files.eof?
60
+ case line = files.getline
61
+ when /^\s*(#.*)?$/
62
+ #skip space and comment.
63
+ when /^%class\s*(\S+)\s*::\s*(\S+)\s*$/
64
+ @target_name = $1
65
+ @generator = Object.const_get("#{$2}Generator").new(self)
66
+ break
67
+ when /^%class\s*(.*?)\s*$/
68
+ @target_name = $1
69
+ @generator = SingleLALRParserGenerator.new(self)
70
+ break
71
+ when /^%defext\s*(.*?)\s*$/
72
+ @target_name = $1
73
+ @generator = ExtensionLALRParserGenerator.new(self)
74
+ break
75
+ else
76
+ error_exit "%class not found."
77
+ end
78
+ end
79
+ @generator.parse_decl
80
+ end
81
+ def error_exit msg, lineno=nil
82
+ lineno ||= files.lineno
83
+ warn "#{files.path}:#{lineno}: #{msg}"
84
+ exit 1
85
+ end
86
+ def warning msg, lineno=nil
87
+ lineno ||= files.lineno
88
+ warn "#{files.path}:#{lineno}: warning: #{msg}"
89
+ end
90
+ end
91
+
92
+ #
93
+ # = grammar part parser
94
+ #
95
+ class GrammarParser
96
+ include FileUtils
97
+ def files
98
+ @d_parser.files
99
+ end
100
+ alias file files
101
+ alias f files
102
+
103
+ private
104
+ GToken = Struct.new(:tag, :value, :name, :lineno)
105
+ def _GToken tag, value, name=nil
106
+ @token = GToken[tag, value, name, lineno]
107
+ return @token
108
+ end
109
+ def parse_grammar
110
+ gettoken
111
+ preRuleList
112
+ parse_rulelist
113
+ postRuleList
114
+ unless @token.tag == nil
115
+ error_exit "syntax error(grammar). "<<
116
+ "unexpected '#{@token.tag}' expect '%%'"
117
+ end
118
+ end
119
+ def parse_rulelist
120
+ preRule
121
+ parse_rule
122
+ postRule
123
+ if @token.tag == :NT
124
+ parse_rulelist
125
+ end
126
+ end
127
+ def parse_rule
128
+ if @token[0] == :NT
129
+ @r = @token.value
130
+ gettoken
131
+ postLhs
132
+
133
+ unless @token.tag == ':'
134
+ error_exit "syntax error(grammar). "<<
135
+ "unexpected '#{@token.tag}' expecting ':'"
136
+ end
137
+ gettoken
138
+
139
+ @nrhs = 0
140
+ preRhsList
141
+ parse_rhslist
142
+ postRhsList
143
+
144
+ unless @token.tag == ';'
145
+ error_exit "syntax error(grammar). " <<
146
+ "unexpected '#{@token[0]}' expecting ';'"
147
+ end
148
+ gettoken
149
+ end
150
+ end
151
+ def parse_rhslist
152
+ @rhs = []; @rhsni = {}; @prec = nil
153
+ @optval = Array.new(@nparam)
154
+ preRhs
155
+ parse_syms
156
+ @g.push Rule[@r, @rhs, @prec]
157
+ postRhs
158
+ @nrhs += 1
159
+
160
+ if @token.tag == '|'
161
+ gettoken
162
+ parse_rhslist
163
+ end
164
+ end
165
+ def parse_syms
166
+ if @token.tag == :NT || @token.tag == :T
167
+ @rhs.push @token.value
168
+ @rhsni[@token.name] = @rhs.size - 1
169
+
170
+ gettoken
171
+
172
+ postSymbol
173
+ parse_syms
174
+ end
175
+ end
176
+
177
+ public
178
+ def gettoken
179
+ while !@line.empty? || !eof?
180
+ getline if @line.empty?
181
+ @oldline = @line
182
+ tag = s = name = val = nil
183
+ until @line.empty? do
184
+ case @line
185
+ when /^\s+/, /^\#.*/ ;
186
+ # skip
187
+ when /^=([a-zA-Z]+)/
188
+ @prec = s = $1.intern
189
+ val = @terms[s] ||= - (@terms.size + 1)
190
+ when /^([a-z][a-z0-9_]*)(-([a-z][_a-z0-9]*))?/
191
+ tag = :NT
192
+ s = $1.intern
193
+ name = $3 ? $3 : $1
194
+ val = @nonterms[s] ||= @nonterms.size
195
+ when /^([A-Z][A-Z0-9_]*)(-([a-z][_a-z0-9]*))?/
196
+ tag = :T
197
+ s = $1.intern
198
+ name = $3 ? $3 : $1
199
+ val = @terms[s] ||= - (@terms.size + 1)
200
+ when /^'(.)'/
201
+ tag = :T
202
+ name = s = $1
203
+ val = @terms[s] ||= - (@terms.size + 1)
204
+ when /^%%/
205
+ return _GToken(nil, nil)
206
+ when /^(.)/
207
+ tag = $&
208
+ val = $&
209
+ else
210
+ raise RuntimeError, "must not happen #{line}"
211
+ end
212
+ @oldline = @line; @line = $'
213
+ @i2s[val] ||= s if val && s
214
+ return _GToken(tag, val, name) if tag
215
+ end
216
+ end
217
+ return _GToken(nil, nil)
218
+ end
219
+
220
+ private
221
+ def preRuleList
222
+ @prerulelist.each{|o, m| o.send m}
223
+ end
224
+ def postRuleList
225
+ @postrulelist.each{|o, m| o.send m}
226
+ end
227
+ def preRule
228
+ @prerule.each{|o, m| o.send m}
229
+ end
230
+ def postRule
231
+ @postrule.each{|o, m| o.send m}
232
+ end
233
+ def postLhs
234
+ @postlhs.each{|o, m| o.send(m)}
235
+ end
236
+ def preRhsList
237
+ @prerhslist.each{|o, m| o.send m}
238
+ end
239
+ def postRhsList
240
+ @postrhslist.each{|o, m| o.send m}
241
+ end
242
+ def preRhs
243
+ @prerhs.each{|o, m| o.send(m)}
244
+ end
245
+ def postRhs
246
+ @postrhs.each{|o, m| o.send(m)}
247
+ end
248
+ def postSymbol
249
+ @postsymbol.each{|o, m| o.send(m)}
250
+ end
251
+
252
+ public
253
+ # get number of param
254
+ def getnparam a = nil
255
+ return nil unless a
256
+ return @nparams[a] if @nparams[a]
257
+ @nparam += 1
258
+ @nparams[a] = @nparam
259
+ end
260
+
261
+ def int_to_sym n
262
+ @i2s[n]
263
+ end
264
+ alias i2s int_to_sym
265
+
266
+ # add nonterm
267
+ # sym:: symbol
268
+ def add_nonterm sym
269
+ isym = @nonterms[sym] = @nonterms.size
270
+ @i2s[isym] = sym
271
+ return isym
272
+ end
273
+
274
+ # get rhs index by name
275
+ # name :: name
276
+ def name_to_rhs_index name
277
+ @rhsni[name]
278
+ end
279
+ alias n2ri name_to_rhs_index
280
+
281
+ # lhs value
282
+ def lhs
283
+ @r
284
+ end
285
+
286
+ attr_accessor :g, :terms, :nonterms, :precs
287
+ attr_accessor :line, :line0, :oldline, :token
288
+ attr_accessor :optouter, :optinner, :optmain, :mixin
289
+ attr_accessor :nparams, :rhs, :nrhs, :rhsni, :nparam, :r, :nrules
290
+ attr_accessor :prerulelist, :postrulelist, :prerule, :postrule
291
+ attr_accessor :postlhs, :prerhslist, :postrhslist
292
+ attr_accessor :prerhs, :postrhs, :postsymbol
293
+ attr_reader :d_parser, :target_name, :table
294
+
295
+ def initialize d_parser
296
+ @yydebug = true
297
+ @d_parser = d_parser
298
+
299
+ @i2s = {}
300
+
301
+ @g = [Rule[0 , [1]]]
302
+ @terms = { nil => -1, false => -2 }
303
+ @nonterms = {'$start' => 0}
304
+
305
+ @optinner = []
306
+ @optouter = []
307
+ @optmain = []
308
+
309
+ @nparams = {}
310
+ @nparam = 1
311
+
312
+ init_hook
313
+ end
314
+
315
+ private
316
+ # make grammar object
317
+ # precs:: prec infos
318
+ def make_grammar precs
319
+ ts = @nonterms.size - 1
320
+ @terms.each{|k,v| @terms[k] = ts - v}
321
+ @g[0].act = Array.new(@nparam-1)
322
+
323
+ @precs = {}
324
+ precs.each_with_index do |p, x|
325
+ p[1].each do |i|
326
+ if @terms[i]
327
+ @precs[@terms[i]] = [p[0], x]
328
+ else
329
+ error_exit "prec error '#{i}'."
330
+ end
331
+ end
332
+ end
333
+ @g.each do |rl|
334
+ rl.r.each_with_index{|i, x| rl.r[x] = ts - i if i < 0}
335
+ rl.prec &&= @precs[@terms[rl.prec]]
336
+ end
337
+ end
338
+ alias mkg make_grammar
339
+
340
+ # initialize hook
341
+ def init_hook
342
+ @prerulelist = []
343
+ @postrulelist = []
344
+
345
+ @prerule = []
346
+ @postrule = []
347
+
348
+ @postlhs = []
349
+
350
+ @postrhslist = []
351
+ @prerhslist = []
352
+
353
+ @prerhs = []
354
+ @postrhs = []
355
+
356
+ @postsymbol = []
357
+ end
358
+
359
+ public
360
+ # extend paser
361
+ # ext:: extension name
362
+ def extend_paser ext
363
+ init_hook
364
+ ext.each do |f,m|
365
+ require f if f
366
+ Object.const_get("#{m}Extension").new.send(:__regext__, self)
367
+ end
368
+ end
369
+
370
+ # get next line
371
+ def getline
372
+ @line0 = @line = files.getline
373
+ end
374
+
375
+ # parse and make LALR(1) table
376
+ # file:: input file object
377
+ # target_name:: class name
378
+ # mixin:: mixin modules
379
+ # precs:: prec infos
380
+ # return:: LALRTable
381
+ def parse(target_name = nil, mixin = [], precs = [])
382
+ @line = @line0 = ''
383
+ @oldline = nil
384
+ @target_name = target_name
385
+ @mixin = mixin
386
+
387
+ parse_grammar
388
+ make_grammar precs
389
+ @table = LALRTable.new(G.new(@g, @terms, @nonterms, @precs))
390
+ end
391
+ end
392
+
393
+ class Generator
394
+ include FileUtils
395
+ def files
396
+ @d_parser.files
397
+ end
398
+ Tmpldir = Depager::Tmpldir
399
+ Tmplfile = "**NOTHING**"
400
+ def tmpldir
401
+ Generator::Tmpldir
402
+ end
403
+ def tmplf
404
+ self.class::Tmplfile
405
+ end
406
+ attr_reader :d_parser
407
+ attr_accessor :optouter, :optinner, :optmain
408
+ attr_accessor :basis_name, :deco, :req
409
+ def initialize d_parser
410
+ @d_parser = d_parser
411
+ @basis_name = nil
412
+
413
+ @deco = []
414
+ @req = []
415
+ @ext = []
416
+
417
+ @optinner = []
418
+ @optouter = []
419
+ @optmain = []
420
+ @precs = []
421
+ @mixin = []
422
+
423
+ @tmpldir = Generator::Tmpldir+'/'
424
+ end
425
+
426
+ def parse_prec
427
+ precs = []
428
+ until files.eof?
429
+ case line = files.getline
430
+ when /^\s*(left|right|nonassoc)\s+(.*)$/
431
+ dir = $1.upcase.intern
432
+ syms = $2.split.map{|i| (i =~ /'(.)'/) ? $1 : i.intern}
433
+ precs.push [dir, syms]
434
+ when /^%\}\s*$/
435
+ break
436
+ else
437
+ error_exit "syntax error(prec).\n> #{line}"
438
+ end
439
+ end
440
+ return precs
441
+ end
442
+
443
+ def parse_block
444
+ val = ''
445
+ until eof?
446
+ line = getline
447
+ break if line =~ /^%\}/
448
+ val.concat line
449
+ end
450
+ return val
451
+ end
452
+
453
+ def parse_common line
454
+ case line
455
+ when /^\s*(#.*)?$/
456
+ #skip space and comment.
457
+ when /^%decorate\s+(.*?)\s*\((.*)\)\s*$/
458
+ @deco.push $1
459
+ @req.push $2
460
+ when /^%decorate\s+(.*?)\s*$/
461
+ @deco.push $1
462
+ when /^%extend\s+(.*?)\s*\(\s*'(.*)'\s*\)\s*$/
463
+ @ext.push [$2.strip, $1] unless @ext.find{|i| i[1] == $1}
464
+ when /^%extend\s+(.*?)\s*$/
465
+ # not implemented yet
466
+ warning "'%extend E' is not implemented yet. " <<
467
+ "use '%extend Ext (filename)' instead.", lineno
468
+ when /^%require\s+'(.+?)'\s*$/
469
+ @req.push "'#{$1}'"
470
+ when /^%mixin\s+(\S+)\s*(\((.+)\)\s*)?$/
471
+ @mixin.push $1
472
+ @req.push $3 if $3
473
+ when /^%inner\s*\{\s*$/
474
+ @optinner.push parse_block
475
+ when /^%outer\s*\{\s*$/
476
+ # obsolete
477
+ warning "'%optouter' is obsolete."
478
+ @optouter.push parse_block
479
+ when /^%main\s*\{\s*$/
480
+ # obsolete
481
+ warning "'%optmain' is obsolete."
482
+ @optmain.push parse_block
483
+ when /^%prec\s*\{\s*$/
484
+ @precs = parse_prec
485
+ else
486
+ warning "syntax error(declaration).\n> #{line}"
487
+ end
488
+ end
489
+ end
490
+
491
+ class SimpleGenerator < Generator
492
+ Tmplfile = 'simple.erb'
493
+ def initialize d_parser
494
+ super
495
+ end
496
+ def out_code g_parser
497
+ ERB.new(File.read("#{tmpldir}/#{tmplf}")).result(binding)
498
+ end
499
+ def parse_decl
500
+ until eof?
501
+ line = getline
502
+ case line
503
+ when /^%%\s*$/
504
+ g_parser = GrammarParser.new(@d_parser)
505
+ g_parser.extend_paser @ext
506
+ g_parser.parse(@d_parser.target_name, @mixin, @precs)
507
+ @optmain.push parse_block
508
+ return out_code(g_parser)
509
+ else
510
+ parse_common(line)
511
+ end
512
+ end
513
+ return nil
514
+ end
515
+ end
516
+
517
+ class SingleLALRParserGenerator < SimpleGenerator
518
+ Tmplfile = 'single_lalr_parser.erb'
519
+ def initialize d_parser
520
+ super
521
+ @basis_name = @d_parser.target_name + '.new()'
522
+ end
523
+ end
524
+
525
+ class ExtensionLALRParserGenerator < Generator
526
+ attr_accessor :regs, :paramkey
527
+ def initialize d_parser
528
+ super
529
+ @basis_name = 'self'
530
+ @paramkey = nil
531
+ @regs = {
532
+ "prerulelist" => nil,
533
+ "postrulelist" => nil,
534
+
535
+ "prerule" => nil,
536
+ "postrule" => nil,
537
+
538
+ "postlhs" => nil,
539
+
540
+ "postrhslist" => nil,
541
+ "prerhslist" => nil,
542
+
543
+ "prerhs" => nil,
544
+ "postrhs" => nil,
545
+ }
546
+ end
547
+
548
+ def parse_decl
549
+ until eof?
550
+ line = getline
551
+ case line
552
+ when /^%hook\s*(.*?)\s*$/
553
+ hs = $1
554
+ mtsk = if hs =~ /\/(([^\/\\]+|\\.)*)\/\s*(skip)?$/
555
+ hs = $`
556
+ [$1, $3 ? true : false]
557
+ end
558
+ hook = hs.split(' ')
559
+ hookname = hook.join('_')
560
+ hook.each{|i| @regs[i] = [i, "#{@d_parser.target_name}_#{hookname}"]}
561
+ @optouter.push(parse_hook(hookname, mtsk))
562
+ when /^%param\s*(.*)\s*$/
563
+ @paramkey = $1
564
+ else
565
+ parse_common(line)
566
+ end
567
+ end
568
+ return out_master_code
569
+ end
570
+
571
+ def parse_hook hookname, mtsk
572
+ inner = ''
573
+ precs = []
574
+ banner = nil
575
+ mixin = [].concat(@mixin)
576
+ target_name = "#{@d_parser.target_name}_#{hookname}"
577
+ until eof?
578
+ line = getline
579
+ case line
580
+ when /^%banner\s*'(([^'\\]+|\\.)*)'\s*$/
581
+ banner = $1
582
+ when /^%inner\s*\{\s*$/
583
+ inner = parse_block
584
+ when /^%mixin\s*(.+?)\s*(\((.+)\)\s*)?$/
585
+ mixin.push $1
586
+ @req.push $3 if $3
587
+ when /^%prec\s*(.*?)\s*$/
588
+ precs = parse_prec
589
+ when /^%%\s*$/
590
+ g_parser = GrammarParser.new(@d_parser)
591
+ g_parser.extend_paser @ext
592
+ g_parser.parse(target_name, mixin, precs)
593
+ g_parser.optinner.push inner
594
+ return out_slave_code(g_parser, mixin, mtsk, banner)
595
+ else
596
+ warning "syntax error(declaration).\n> #{line}", lineno
597
+ end
598
+ end
599
+ end
600
+
601
+ def out_slave_code g_parser, mixin, mtsk, banner
602
+ ERB.new(File.read("#{tmpldir}/extension_lalr_slave.erb")).result(binding)
603
+ end
604
+ def out_master_code
605
+ ERB.new(File.read("#{tmpldir}/extension_lalr_master.erb")).result(binding)
606
+ end
607
+ end
608
+ end