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.
- data/ChangeLog +4 -0
- data/Manifest.txt +52 -0
- data/README.en +64 -0
- data/README.ja +128 -0
- data/bin/depager +47 -0
- data/data/depager/misc/depager-mode.el +209 -0
- data/data/depager/sample/extension/paction.dr +15 -0
- data/data/depager/sample/extension/pactiontest.dr +14 -0
- data/data/depager/sample/pl0d/pl0ds.dr +334 -0
- data/data/depager/sample/pl0d/pl0test.pl0 +34 -0
- data/data/depager/sample/sample_calc/calc.action.dr +33 -0
- data/data/depager/sample/sample_calc/calc.astdf.dr +54 -0
- data/data/depager/sample/sample_calc/calc.astl.action.dr +66 -0
- data/data/depager/sample/sample_calc/calc.astl.dr +55 -0
- data/data/depager/sample/sample_calc/calc.atree.dr +43 -0
- data/data/depager/sample/sample_calc/calc.cst.dr +45 -0
- data/data/depager/sample/sample_calc/calc.dr +43 -0
- data/data/depager/sample/sample_calc/calc.lex.dr +29 -0
- data/data/depager/sample/sample_calc/calc.nvaction.dr +33 -0
- data/data/depager/sample/sample_calc/calc_prec.nvaction.dr +31 -0
- data/data/depager/sample/slex_test/slextest1.dr +37 -0
- data/data/depager/sample/slex_test/slextest2.dr +33 -0
- data/lib/depager.rb +608 -0
- data/lib/depager/Rakefile +30 -0
- data/lib/depager/action.rb +47 -0
- data/lib/depager/ast_base.dr +232 -0
- data/lib/depager/ast_base.rb +1249 -0
- data/lib/depager/astdf.rb +10 -0
- data/lib/depager/astl.rb +14 -0
- data/lib/depager/atree.dr +55 -0
- data/lib/depager/atree.rb +336 -0
- data/lib/depager/cst.dr +182 -0
- data/lib/depager/cst.rb +625 -0
- data/lib/depager/lex.dr +76 -0
- data/lib/depager/lex.rb +306 -0
- data/lib/depager/lr.rb +604 -0
- data/lib/depager/nvaction.rb +21 -0
- data/lib/depager/parse_action.rb +24 -0
- data/lib/depager/parser.rb +248 -0
- data/lib/depager/psrtmpl.rb +33 -0
- data/lib/depager/slex.dr +161 -0
- data/lib/depager/slex.rb +646 -0
- data/lib/depager/srp.rb +50 -0
- data/lib/depager/template/astdf.erbs +57 -0
- data/lib/depager/template/astl.erbs +57 -0
- data/lib/depager/template/extension_lalr_master.erb +51 -0
- data/lib/depager/template/extension_lalr_slave.erb +107 -0
- data/lib/depager/template/simple.erb +21 -0
- data/lib/depager/template/single_lalr_parser.erb +97 -0
- data/lib/depager/utils.rb +355 -0
- data/lib/depager/version.rb +9 -0
- data/setup.rb +1585 -0
- 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)
|
data/lib/depager.rb
ADDED
@@ -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
|