depager 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
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