mkbison 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ module Bison
2
+ class Rule
3
+ attr_reader :name, :components
4
+ attr_accessor :location
5
+
6
+ def initialize(name, components=[])
7
+ @name, @components = name, components
8
+ components.each_with_index{ |x, i| x.index = i; x.rule = self }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ module Bison
2
+ class Sequence
3
+ attr_accessor :rule, :index
4
+ attr_reader :elements
5
+
6
+ def initialize
7
+ @elements = []
8
+ end
9
+
10
+ def <<(element)
11
+ if Bison::Action === element
12
+ element.predecessors = elements.clone
13
+ end
14
+ element.sequence = self
15
+ elements << element
16
+ self
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module Bison
2
+ class Token
3
+ attr_accessor :name
4
+ attr_accessor :number
5
+ attr_accessor :associativity
6
+
7
+ def initialize(name, assoc=nil)
8
+ self.name = name
9
+ self.associativity = assoc
10
+ end
11
+
12
+ def left?
13
+ associativity == :left
14
+ end
15
+
16
+ def right?
17
+ associativity == :right
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Bison
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,123 @@
1
+
2
+ class BisonParser
3
+ attr_accessor :section
4
+
5
+ def lex
6
+ x = real_lex
7
+ Tokens.constants.each do |const|
8
+ if Tokens.const_get(const) == x
9
+ warn "Lex'd #{const}\t: #{lex_value.inspect}" if ENV['DEBUG_GRAMMAR']
10
+ return x
11
+ end
12
+ end
13
+
14
+ warn "Lex'd #{x.inspect}" if ENV['DEBUG_GRAMMAR']
15
+
16
+ x
17
+ end
18
+
19
+ def real_lex
20
+ self.section ||= 0
21
+ self.lex_value = nil
22
+
23
+ if section == 2
24
+ self.lex_value = io.read
25
+ self.section += 2
26
+ return Tokens::ACTIONS
27
+ end
28
+
29
+ # skip space
30
+ while true
31
+ while (c = self.read) && c =~ /\s/
32
+ end
33
+
34
+ if c == '#'
35
+ while (char = self.read) && char != "\n"
36
+ end
37
+ else
38
+ break
39
+ end
40
+ end
41
+
42
+ return nil unless c
43
+
44
+ case c
45
+ when ':'
46
+ return Tokens::COLON
47
+ when ';'
48
+ return Tokens::SEMICOLON
49
+ when '|'
50
+ return Tokens::PIPE
51
+ when '%'
52
+ if self.peak == '%'
53
+ self.read
54
+ self.section += 1
55
+ return Tokens::DOUBLE_HASH
56
+ end
57
+ return Tokens::HASH
58
+ when '['
59
+ return Tokens::LBRACK
60
+ when ']'
61
+ return Tokens::RBRACK
62
+ when '{'
63
+ nesting = 1
64
+ action = ''
65
+ while (c = self.read) && nesting > 0
66
+ nesting += 1 if c == '{'
67
+ nesting -= 1 if c == '}'
68
+ action << c unless nesting.zero?
69
+ end
70
+ self.lex_value = action
71
+ return Tokens::ACTIONS
72
+ when '0'..'9'
73
+ number = c
74
+ while (c = self.peak) && ('0'..'9').include?(c)
75
+ number << self.read
76
+ end
77
+ self.lex_value = number.to_i
78
+ return Tokens::NUMBER
79
+ when '"'
80
+ string = ''
81
+ while (c = self.read) && c != '"'
82
+ string << c
83
+ end
84
+ self.lex_value = string
85
+ return Tokens::STRING
86
+ when "'"
87
+ string = ''
88
+ while (c = self.read) && c != "'"
89
+ string << c
90
+ end
91
+ self.lex_value = string
92
+ return Tokens::STRING
93
+ end
94
+
95
+ if c =~ /\w/
96
+ string = c
97
+ while (c = self.peak) && c =~ /\w/
98
+ self.read
99
+ string << c
100
+ end
101
+
102
+ if section.zero? && string == 'token'
103
+ return Tokens::KW_TOKEN
104
+ elsif section.zero? && string == 'left'
105
+ return Tokens::KW_LEFT
106
+ elsif section.zero? && string == 'right'
107
+ return Tokens::KW_RIGHT
108
+ else
109
+ self.lex_value = string
110
+ return Tokens::IDENTIFIER
111
+ end
112
+ end
113
+
114
+ warn "Yielding literal #{c.inspect}"
115
+
116
+ return c.ord
117
+ end
118
+ end
119
+
120
+
121
+ require 'bison_parser/base'
122
+ require 'bison_parser/actions'
123
+ require 'bison_parser/bison_parser'
@@ -0,0 +1,81 @@
1
+ class BisonParser
2
+ class Actions
3
+ attr_accessor :parser, :result
4
+
5
+ def _0_grammar_file(tokens, rules, code)
6
+ self.result = Bison::GrammarFile.new(tokens, rules, code)
7
+ end
8
+
9
+ def _0_optional_code()
10
+ nil
11
+ end
12
+
13
+ def _1_optional_code(actions)
14
+ actions
15
+ end
16
+
17
+ def _0_token_list()
18
+ []
19
+ end
20
+
21
+ def _1_token_list(list, token)
22
+ list << token
23
+ end
24
+
25
+ def _0_token(name)
26
+ Bison::Token.new(name)
27
+ end
28
+
29
+ def _1_token(name)
30
+ Bison::Token.new(name, :left)
31
+ end
32
+
33
+ def _2_token(name)
34
+ Bison::Token.new(name, :right)
35
+ end
36
+
37
+ def _3_token(token, num)
38
+ token.tap{ |t| t.number = num }
39
+ end
40
+
41
+ def _0_grammar_rules()
42
+ []
43
+ end
44
+
45
+ def _1_grammar_rules(list, rule)
46
+ list << rule
47
+ end
48
+
49
+ def _0_grammar_rule(name, components)
50
+ Bison::Rule.new(name, components).tap{ |r| r.location = @name }
51
+ end
52
+
53
+ def _0_components(sequence)
54
+ [sequence]
55
+ end
56
+
57
+ def _1_components(sequences, sequence)
58
+ sequences << sequence
59
+ end
60
+
61
+ def _0_sequence()
62
+ Bison::Sequence.new
63
+ end
64
+
65
+ def _1_sequence(sequence, code)
66
+ sequence << Bison::Action.new(code).tap{ |a| a.location = @code }
67
+ end
68
+
69
+ def _2_sequence(sequence, follower)
70
+ sequence << Bison::Nonterminal.new(follower).tap{ |x| x.location = @follower }
71
+ end
72
+
73
+ def _3_sequence(sequence, follower, tag)
74
+ sequence << Bison::Nonterminal.new(follower, tag).tap{ |x| x.location = @follower }
75
+ end
76
+
77
+ def _4_sequence(sequence, follower)
78
+ sequence << Bison::String.new(follower).tap{ |x| x.location = @follower }
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,49 @@
1
+ class BisonParser
2
+ attr_reader :io
3
+ attr_accessor :lex_value, :token_row, :token_col, :row, :col
4
+ attr_accessor :source, :result
5
+
6
+ module Base
7
+ def initialize(io)
8
+ if String === io
9
+ io = ::File.open(io, 'r')
10
+ end
11
+ @source = io.respond_to?(:path) ? io.path : nil
12
+ @io, @row, @col = io, 1, 0
13
+ end
14
+
15
+ def read
16
+ io.read(1).tap do |c|
17
+ if c == "\n"
18
+ self.row += 1
19
+ self.col = 0
20
+ elsif c
21
+ self.col += 1
22
+ end
23
+ end
24
+ end
25
+
26
+ def peak
27
+ io.read(1).tap{ |c| io.ungetc(c) if c }
28
+ end
29
+
30
+ def begin_token
31
+ self.token_row = row
32
+ self.token_col = col
33
+ end
34
+
35
+ def error(msg, row, col)
36
+ raise Error.new(msg, source, row, col)
37
+ end
38
+ end
39
+
40
+ include Base
41
+
42
+ class Error < ::Exception
43
+ attr_reader :message
44
+ def initialize(msg, source, row, col)
45
+ source ||= '-'
46
+ @message = "#{source}:#{row}.#{col} #{msg}"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'bison/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "mkbison"
7
+ spec.version = Bison::VERSION
8
+ spec.authors = ["Peter Woo"]
9
+ spec.email = ["peter@wioux.net"]
10
+ spec.summary = %q{Tool to generate bison parser C extensions}
11
+ spec.homepage = ""
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.extensions = %w[ext/bison_parser/extconf.rb]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rake-compiler"
24
+ end
@@ -0,0 +1,10 @@
1
+ class <%= name %>
2
+ class Actions
3
+ attr_accessor :parser, :result
4
+ <% rules.map(&:components).flatten.map(&:elements).flatten.grep(Bison::Action).each_with_index do |action, i| %>
5
+ def <%= action.name %>(<%= action.predecessor_tags.values.join(', ') %>)
6
+ <%= action.code.strip %>
7
+ end
8
+ <% end -%>
9
+ end
10
+ end
@@ -0,0 +1,49 @@
1
+ class <%= name %>
2
+ attr_reader :io
3
+ attr_accessor :lex_value, :token_row, :token_col, :row, :col
4
+ attr_accessor :source, :result
5
+
6
+ module Base
7
+ def initialize(io)
8
+ if String === io
9
+ io = ::File.open(io, 'r')
10
+ end
11
+ @source = io.respond_to?(:path) ? io.path : nil
12
+ @io, @row, @col = io, 1, 0
13
+ end
14
+
15
+ def read
16
+ io.read(1).tap do |c|
17
+ if c == "\n"
18
+ self.row += 1
19
+ self.col = 0
20
+ elsif c
21
+ self.col += 1
22
+ end
23
+ end
24
+ end
25
+
26
+ def peak
27
+ io.read(1).tap{ |c| io.ungetc(c) if c }
28
+ end
29
+
30
+ def begin_token
31
+ self.token_row = row
32
+ self.token_col = col
33
+ end
34
+
35
+ def error(msg, row, col)
36
+ raise Error.new(msg, source, row, col)
37
+ end
38
+ end
39
+
40
+ include Base
41
+
42
+ class Error < ::Exception
43
+ attr_reader :message
44
+ def initialize(msg, source, row, col)
45
+ source ||= '-'
46
+ @message = "#{source}:#{row}.#{col} #{msg}"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,10 @@
1
+ <% if code %>
2
+ <%= code.strip %>
3
+ <% else %>
4
+ class <%= name %>
5
+ end
6
+ <% end %>
7
+
8
+ require '<%= uname %>/base'
9
+ require '<%= uname %>/actions'
10
+ require '<%= uname %>/<%= uname %>'
@@ -0,0 +1,9 @@
1
+ require 'mkmf'
2
+
3
+ output = "#{File.dirname(__FILE__)}/<%= uname %>.c"
4
+ bison_file = "#{File.dirname(__FILE__)}/<%= uname %>.y"
5
+
6
+ bison = ENV['BISON_PATH'] || 'bison'
7
+ system(bison, '-o', output, bison_file)
8
+
9
+ create_makefile '<%= uname %>/<%= uname %>'
@@ -0,0 +1,123 @@
1
+
2
+ <% tokens.each do |token| -%>
3
+ <% if token.number -%>
4
+ %token <%= token.name %><%= "\t" * (4 - token.name.length/8)%><%= token.number %>
5
+ <% else -%>
6
+ %token <%= token.name %>
7
+ <% end -%>
8
+ <% end -%>
9
+
10
+ <% tokens.select{|t| t.left? || t.right?}.each do |token| -%>
11
+ <%= token.left? ? '%left' : '%right' %> <%= token.name %>
12
+ <% end -%>
13
+
14
+ %define api.pure true
15
+ %define parse.error verbose
16
+ %parse-param { VALUE __actions }
17
+ %lex-param { VALUE __actions }
18
+ %locations
19
+
20
+ %{
21
+ #include <ruby.h>
22
+ #define YYSTYPE VALUE
23
+ %}
24
+
25
+ %code provides {
26
+ static int yylex(YYSTYPE *, YYLTYPE *, VALUE);
27
+ static void yyerror(YYLTYPE *, VALUE, const char *);
28
+ }
29
+
30
+ %%
31
+
32
+ <% rules.each do |rule| -%>
33
+ <%= rule.name %>:
34
+ <% rule.components.each_with_index do |seq, i| -%>
35
+ <%= "|\n" unless i.zero? -%>
36
+ <%= ' '+seq.elements.map(&:to_bison).join(' ') unless seq.elements.empty? %>
37
+ <% if !(Bison::Action === seq.elements[-1]) -%>
38
+ <% if seq.elements.grep(Bison::Nonterminal).empty? -%>
39
+ { $$ = Qnil; }
40
+ <% else -%>
41
+ { $$ = $<%= seq.elements.find_index{ |x| Bison::Nonterminal === x } + 1%>; }
42
+ <% end %>
43
+ <% end -%>
44
+ <% end -%>
45
+ ;
46
+
47
+ <% end -%>
48
+
49
+ %%
50
+
51
+ static VALUE c<%= name %>;
52
+ static VALUE c<%= name %>Tokens;
53
+ static VALUE c<%= name %>Actions;
54
+
55
+ static VALUE <%= uname %>_parse(VALUE);
56
+
57
+ void Init_<%= uname %>(void) {
58
+ c<%= name %> = rb_define_class("<%= name %>", rb_cObject);
59
+ c<%= name %>Tokens = rb_define_module_under(c<%= name %>, "Tokens");
60
+ c<%= name %>Actions = rb_define_class_under(c<%= name %>, "Actions", rb_cObject);
61
+
62
+ <% tokens.each do |token| -%>
63
+ rb_define_const(c<%= name %>Tokens, "<%= token.name %>", INT2FIX(<%= token.name %>));
64
+ <% end -%>
65
+
66
+ rb_define_method(c<%= name %>, "parse", <%= uname %>_parse, 0);
67
+ }
68
+
69
+ VALUE <%= uname %>_parse(VALUE self) {
70
+ VALUE actions = rb_funcall(c<%= name %>Actions, rb_intern("new"), 0);
71
+ rb_funcall(actions, rb_intern("parser="), 1, self);
72
+ if (yyparse(actions))
73
+ return Qnil;
74
+ return rb_funcall(actions, rb_intern("result"), 0);
75
+ }
76
+
77
+ static void yyerror(YYLTYPE *loc, VALUE actions, const char *msg) {
78
+ VALUE parser = rb_funcall(actions, rb_intern("parser"), 0);
79
+ rb_funcall(parser, rb_intern("error"), 3,
80
+ rb_str_new_cstr(msg),
81
+ INT2FIX(loc->first_line),
82
+ INT2FIX(loc->first_column));
83
+ }
84
+
85
+ static int yylex(YYSTYPE *lval, YYLTYPE *lloc, VALUE actions) {
86
+ int c;
87
+ VALUE parser, value, vtok;
88
+
89
+ parser = rb_funcall(actions, rb_intern("parser"), 0);
90
+
91
+ rb_funcall(parser, rb_intern("lex_value="), 1, Qnil);
92
+ rb_funcall(parser, rb_intern("token_row="), 1, INT2FIX(lloc->last_line));
93
+ rb_funcall(parser, rb_intern("token_col="), 1, INT2FIX(lloc->last_column));
94
+
95
+ vtok = rb_funcall(parser, rb_intern("lex"), 0);
96
+ value = rb_funcall(parser, rb_intern("lex_value"), 0);
97
+
98
+ lloc->first_line = FIX2INT(rb_funcall(parser, rb_intern("token_row"), 0));
99
+ lloc->first_column = FIX2INT(rb_funcall(parser, rb_intern("token_col"), 0));
100
+ lloc->last_line = FIX2INT(rb_funcall(parser, rb_intern("row"), 0));
101
+ lloc->last_column = FIX2INT(rb_funcall(parser, rb_intern("col"), 0));
102
+
103
+ if (vtok == Qnil) {
104
+ *lval = Qnil;
105
+ // fprintf(stderr, "parse is nil\n");
106
+ return 0;
107
+ }
108
+
109
+ if (vtok & 1) {
110
+ *lval = value;
111
+ // fprintf(stderr, "parse is int: %d\n", FIX2INT(vtok));
112
+ return FIX2INT(vtok);
113
+ }
114
+
115
+ if (RBASIC(vtok)->klass == rb_cString) {
116
+ c = StringValueCStr(vtok)[0];
117
+ *lval = rb_sprintf("%c", c);
118
+ // fprintf(stderr, "parse is char: '%c' (%d)\n", c, (int)c);
119
+ return c;
120
+ }
121
+
122
+ return 0;
123
+ }