mkbison 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95b6da8ba8118a59aede83a038e4f944bc775af0
4
- data.tar.gz: 324be9460b8a0a91c9ca3e5762169bb590dbe66c
3
+ metadata.gz: 4953dfa30988cbe416adf37cf53b7cc7cb6650e5
4
+ data.tar.gz: 4d2ca4c185047779a8f1aa998ee27b512ae161f7
5
5
  SHA512:
6
- metadata.gz: cafb5be27276443cdcda7a92314391c8a4c44e57327c5fe9169ec1985724743ac473eac8deb610fe1570a4977289da8df6047ac6fdc5db4b7d805332eb03f7cd
7
- data.tar.gz: 65ecb89dde9730af99122599bc73aef47198274e823ba1708259c01fa0ea26e1b7ed73fc872823b3f581a4cb787afaf3b041e863a5b1398ce3e0c65452a880ba
6
+ metadata.gz: 3b34b3be1c7e9212793c7b7a4d3efb4bed4ac290e575a54b95f8d0c3c258ed4b67d6e1c7422f7ebd86026ebeaec2c4a634a1813a29805c33e6d9dc6861cd96b6
7
+ data.tar.gz: 634ec92aa22ec51f382d316f32ea70c152f9a835ba40ccc802a2bb7166eef13b9a0cb3dc0d64fd5e031cd92c5b0031d58d893890a04d21252271a50be0e50e0d
data/.gitignore CHANGED
@@ -20,3 +20,6 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
+
24
+ examples/*/ext
25
+ examples/*/lib
data/README.md CHANGED
@@ -1,43 +1,31 @@
1
1
  # mkbison
2
2
 
3
- TODO: Write a gem description
3
+ `mkbison` is a tool to create native ruby extensions containing [GNU Bison](https://www.gnu.org/software/bison/) generated LALR(1) grammar parsers.
4
4
 
5
5
  ## Installation
6
6
 
7
- Add this line to your application's Gemfile:
7
+ Add these lines to your application's Gemfile:
8
8
 
9
9
  gem 'mkbison'
10
+ gem 'rake-compiler'
10
11
 
11
- And then execute:
12
-
13
- $ bundle
14
-
15
- Or install it yourself as:
16
-
17
- $ gem install mkbison
18
-
19
- You'll need to install [GNU Bison](https://www.gnu.org/software/bison/) as well, e.g.:
12
+ You'll need to install a GNU Bison version >= 3.0.0 as well, with e.g.:
20
13
 
21
14
  $ sudo apt-get install bison
22
15
 
23
16
  ## Usage and Example
24
17
 
25
- The gem installs a command `mkbison` which translates `.rby` files into `.y` Bison grammar files, and generates a native ruby extension to expose the resulting parser.
26
-
27
- `.rby` files contain a grammar definition and ruby code. Their syntax mostly mirrors that of Bison grammar files, with the following differences:
18
+ `mkbison` operates on grammar files with a syntax which mostly mirrors the Bison grammar. For example, here is a file which describes basic arithmetic:
28
19
 
29
- * Actions are written in ruby, rather than C (as is the lex section).
30
- * Positional references to semantic values are not allowed.
31
- * [Named references](http://www.gnu.org/software/bison/manual/html_node/Named-References.html) should not use a dollar sign `$`.
20
+ **[arithmetic.rby](https://github.com/wioux/mkbison/blob/master/examples/arithmetic/arithmetic.rby)**
21
+ ```yacc
32
22
 
33
- For example, here is a mkbison grammar for parsing very simple arithmetic expressions:
34
-
35
- **arithmetic.rby**
36
- ```
37
23
  %token NUMBER
24
+ %token LPAREN
25
+ %token RPAREN
38
26
 
39
- %left OP_PLUS
40
- %left OP_MINUS
27
+ %left OP_PLUS OP_MINUS
28
+ %left OP_TIMES OP_OVER
41
29
 
42
30
  %%
43
31
 
@@ -48,8 +36,14 @@ arithmetic:
48
36
 
49
37
  expression :
50
38
  NUMBER
39
+ | OP_MINUS expression[x]
40
+ { -x }
41
+ | LPAREN expression[x] RPAREN
42
+ { x }
51
43
  | addition
52
44
  | subtraction
45
+ | multiplication
46
+ | division
53
47
  ;
54
48
 
55
49
  addition :
@@ -62,30 +56,24 @@ subtraction :
62
56
  { left - right }
63
57
  ;
64
58
 
59
+ multiplication:
60
+ expression[left] OP_TIMES expression[right]
61
+ { left * right }
62
+ ;
63
+
64
+ division:
65
+ expression[left] OP_OVER expression[right]
66
+ { left / right }
67
+ ;
68
+
65
69
  %%
66
70
 
67
71
  class Arithmetic
68
72
  def lex
69
- # skip space
70
- while true
71
- while (c = self.read) && c =~ /\s/
72
- end
73
-
74
- if c == '#'
75
- while (char = self.read) && char != "\n"
76
- end
77
- else
78
- break
79
- end
80
- end
81
-
73
+ c = read_over_whitespace
82
74
  case c
83
75
  when '0'..'9'
84
- number = c
85
- while (c = self.peak) && ('0'..'9').include?(c)
86
- number << self.read
87
- end
88
-
76
+ number = read_integer(c)
89
77
  self.lex_value = number.to_i
90
78
  return Tokens::NUMBER
91
79
 
@@ -94,30 +82,65 @@ class Arithmetic
94
82
 
95
83
  when '-'
96
84
  return Tokens::OP_MINUS
97
- end
98
85
 
99
- nil
86
+ when '*'
87
+ return Tokens::OP_TIMES
88
+
89
+ when '/'
90
+ return Tokens::OP_OVER
91
+
92
+ when '('
93
+ return Tokens::LPAREN
94
+
95
+ when ')'
96
+ return Tokens::RPAREN
97
+
98
+ else
99
+ return nil
100
+ end
100
101
  end
101
102
  end
102
103
  ```
103
104
 
104
- To translate it into a Bison grammar file, run
105
+ The structure here should be recognizable to those familiar with GNU Bison. If you aren't, you might want to [read up on its usage](https://www.gnu.org/software/bison/manual/html_node/index.html) before using `mkbison`.
105
106
 
106
- $ bundle exec mkbison -n Arithmetic -o . arithmetic.rby
107
- $ rake compile
107
+ There are three sections:
108
+
109
+ 1) Token and precedence definitions
110
+ 2) The description of the grammar
111
+ 3) The lexing implementation
112
+
113
+ To compile this into a ruby extension which we can use to calculate basic arithmetic expressions, first run `mkbison`:
114
+
115
+ $ bundle exec mkbison -n Arithmetic arithmetic.rby
116
+
117
+ This creates the ruby extension in the current directory (under `lib/` and `ext/` directories). The Bison translation of the grammar can be found at `ext/arithmetic/arithmetic.y`. Once compiled, we'll be able to require it as `'arithmetic'` and use it with `Arithmetic.new(expression).parse`.
118
+
119
+ Next we'll need to create a `rake` task as follows:
120
+
121
+ **[Rakefile](https://github.com/wioux/mkbison/blob/master/examples/arithmetic/Rakefile)**
122
+ ```ruby
123
+ require "rake/extensiontask"
124
+
125
+ Rake::ExtensionTask.new "arithmetic" do |ext|
126
+ ext.lib_dir = "lib/arithmetic"
127
+ end
128
+ ```
108
129
 
109
- This will generate and build a native extension named `arithmetic` in the current directory. A class named `Arithmetic` exposes the grammar parser. We can perform calculations now with `Arithmetic.new(expression).parse` which will return the result (or raise an exception if a syntax error is encountered).
130
+ Once we have that, we can compile our extension simply by running
131
+
132
+ $ rake compile
110
133
 
111
134
  ## TODO
135
+ * Add tests
136
+ * Support string/character literals in grammar rules
112
137
  * Automatically create Rakefile task
113
- * Change the parsers initialize() behavior (don't assume argument is file path)
114
-
115
- * Seems like you can hit EOF in the middle of action block and get wrong error msg
116
- * Benchmark -- what takes so long on the koa grammar?
117
138
  * Write to temp files, then move them into place
118
139
  * Move base module into the c extension and document the lexing helpers
140
+ * Seems like you can hit EOF in the middle of action block and get wrong error msg
141
+ * Benchmark -- what takes so long on the koa grammar?
119
142
 
120
- Not all Bison features are supported yet.
143
+ Not all Bison features are supported yet...
121
144
 
122
145
  ## Contributing
123
146
 
data/bin/mkbison CHANGED
@@ -17,6 +17,7 @@ def underscore(name)
17
17
  end
18
18
 
19
19
  options = OpenStruct.new
20
+ options.output = '.'
20
21
 
21
22
  opts = OptionParser.new do |opts|
22
23
  opts.banner += ' grammar_file'
@@ -39,7 +40,7 @@ options.name or abort(opts.help)
39
40
  options.output or abort(opts.help)
40
41
 
41
42
  begin
42
- bison = BisonParser.new(grammar_file).parse
43
+ bison = BisonParser.new(File.open(grammar_file, 'r')).parse
43
44
  rescue BisonParser::Error => e
44
45
  abort(e.message)
45
46
  end
@@ -72,6 +73,7 @@ Tempfile.new('bison-output.c').tap do |output|
72
73
  bison = Cocaine::CommandLine.new(ENV['BISON_PATH'] || 'bison', '-o :out :in')
73
74
  begin
74
75
  bison.run(in: bison_file.path, out: output.path)
76
+ warn bison.command_error_output
75
77
  rescue Cocaine::CommandNotFoundError => e
76
78
  warn("The bison command was not found on this system. " +
77
79
  "Make sure to install it before attempting rake compile.")
data/bison_parser.rby CHANGED
@@ -68,8 +68,7 @@ grammar_rule:
68
68
  ;
69
69
 
70
70
  components:
71
- { [] }
72
- | sequence[sequence]
71
+ sequence[sequence]
73
72
  { [sequence] }
74
73
  |
75
74
  components[sequences] PIPE sequence[sequence]
@@ -104,19 +103,7 @@ class BisonParser
104
103
  return Tokens::ACTIONS
105
104
  end
106
105
 
107
- # skip space
108
- while true
109
- while (c = self.read) && c =~ /\s/
110
- end
111
-
112
- if c == '#'
113
- while (char = self.read) && char != "\n"
114
- end
115
- else
116
- break
117
- end
118
- end
119
-
106
+ c = read_over_whitespace(line_comment_prefix: '#')
120
107
  return nil unless c
121
108
 
122
109
  case c
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'mkbison', path: '../..'
4
+ gem 'rake-compiler'
@@ -0,0 +1,5 @@
1
+ require "rake/extensiontask"
2
+
3
+ Rake::ExtensionTask.new "arithmetic" do |ext|
4
+ ext.lib_dir = "lib/arithmetic"
5
+ end
@@ -0,0 +1,80 @@
1
+ %token NUMBER
2
+ %token LPAREN
3
+ %token RPAREN
4
+
5
+ %left OP_PLUS OP_MINUS
6
+ %left OP_TIMES OP_OVER
7
+
8
+ %%
9
+
10
+ arithmetic:
11
+ expression[x]
12
+ { self.result = x }
13
+ ;
14
+
15
+ expression :
16
+ NUMBER
17
+ | OP_MINUS expression[x]
18
+ { -x }
19
+ | LPAREN expression[x] RPAREN
20
+ { x }
21
+ | addition
22
+ | subtraction
23
+ | multiplication
24
+ | division
25
+ ;
26
+
27
+ addition :
28
+ expression[left] OP_PLUS expression[right]
29
+ { left + right }
30
+ ;
31
+
32
+ subtraction :
33
+ expression[left] OP_MINUS expression[right]
34
+ { left - right }
35
+ ;
36
+
37
+ multiplication:
38
+ expression[left] OP_TIMES expression[right]
39
+ { left * right }
40
+ ;
41
+
42
+ division:
43
+ expression[left] OP_OVER expression[right]
44
+ { left / right }
45
+ ;
46
+
47
+ %%
48
+
49
+ class Arithmetic
50
+ def lex
51
+ c = read_over_whitespace
52
+ case c
53
+ when '0'..'9'
54
+ number = read_integer(c)
55
+ self.lex_value = number.to_i
56
+ return Tokens::NUMBER
57
+
58
+ when '+'
59
+ return Tokens::OP_PLUS
60
+
61
+ when '-'
62
+ return Tokens::OP_MINUS
63
+
64
+ when '*'
65
+ return Tokens::OP_TIMES
66
+
67
+ when '/'
68
+ return Tokens::OP_OVER
69
+
70
+ when '('
71
+ return Tokens::LPAREN
72
+
73
+ when ')'
74
+ return Tokens::RPAREN
75
+
76
+ else
77
+ return nil
78
+ end
79
+ end
80
+ end
@@ -403,7 +403,7 @@ union yyalloc
403
403
  /* YYNNTS -- Number of nonterminals. */
404
404
  #define YYNNTS 10
405
405
  /* YYNRULES -- Number of rules. */
406
- #define YYNRULES 22
406
+ #define YYNRULES 21
407
407
  /* YYNSTATES -- Number of states. */
408
408
  #define YYNSTATES 33
409
409
 
@@ -454,8 +454,8 @@ static const yytype_uint8 yytranslate[] =
454
454
  static const yytype_uint8 yyrline[] =
455
455
  {
456
456
  0, 37, 37, 50, 56, 67, 73, 84, 92, 96,
457
- 107, 115, 123, 135, 141, 152, 164, 170, 178, 190,
458
- 196, 205, 214
457
+ 107, 115, 123, 135, 141, 152, 163, 171, 183, 189,
458
+ 198, 207
459
459
  };
460
460
  #endif
461
461
 
@@ -482,12 +482,12 @@ static const yytype_uint16 yytoknum[] =
482
482
  };
483
483
  # endif
484
484
 
485
- #define YYPACT_NINF -8
485
+ #define YYPACT_NINF -9
486
486
 
487
487
  #define yypact_value_is_default(Yystate) \
488
- (!!((Yystate) == (-8)))
488
+ (!!((Yystate) == (-9)))
489
489
 
490
- #define YYTABLE_NINF -20
490
+ #define YYTABLE_NINF -1
491
491
 
492
492
  #define yytable_value_is_error(Yytable_value) \
493
493
  0
@@ -496,10 +496,10 @@ static const yytype_uint16 yytoknum[] =
496
496
  STATE-NUM. */
497
497
  static const yytype_int8 yypact[] =
498
498
  {
499
- -8, 10, -7, -8, -6, -8, 8, 12, 13, 14,
500
- 15, -1, -8, -8, -8, -8, -8, 16, 3, -8,
501
- -8, -3, -8, -4, -2, -8, -8, 17, -8, -2,
502
- 18, 11, -8
499
+ -9, 9, -8, -9, -7, -9, 7, 11, 12, 13,
500
+ 14, -2, -9, -9, -9, -9, -9, 6, 2, -9,
501
+ -9, -9, -9, -5, -3, -9, -9, 15, -9, -3,
502
+ 16, 17, -9
503
503
  };
504
504
 
505
505
  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -509,14 +509,14 @@ static const yytype_uint8 yydefact[] =
509
509
  {
510
510
  5, 0, 0, 1, 0, 13, 6, 8, 0, 0,
511
511
  0, 3, 9, 12, 7, 10, 11, 0, 0, 2,
512
- 14, 16, 4, 0, 17, 15, 19, 21, 20, 18,
513
- 0, 0, 22
512
+ 14, 18, 4, 0, 16, 15, 18, 20, 19, 17,
513
+ 0, 0, 21
514
514
  };
515
515
 
516
516
  /* YYPGOTO[NTERM-NUM]. */
517
517
  static const yytype_int8 yypgoto[] =
518
518
  {
519
- -8, -8, -8, -8, -8, -8, -8, -8, -8, 0
519
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -6
520
520
  };
521
521
 
522
522
  /* YYDEFGOTO[NTERM-NUM]. */
@@ -528,18 +528,18 @@ static const yytype_int8 yydefgoto[] =
528
528
  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
529
529
  positive, shift that token. If negative, reduce the rule whose
530
530
  number is the opposite. If YYTABLE_NINF, syntax error. */
531
- static const yytype_int8 yytable[] =
531
+ static const yytype_uint8 yytable[] =
532
532
  {
533
- -19, 27, 17, 25, 4, 5, 26, 8, 9, 10,
534
- 3, 18, 12, -19, 28, 13, 14, 15, 16, 22,
535
- 32, 31, 21, 0, 0, 30, 29
533
+ 27, 17, 25, 4, 5, 26, 8, 9, 10, 3,
534
+ 18, 12, 21, 28, 13, 14, 15, 16, 22, 31,
535
+ 29, 0, 0, 30, 0, 0, 32
536
536
  };
537
537
 
538
538
  static const yytype_int8 yycheck[] =
539
539
  {
540
- 3, 3, 3, 7, 11, 12, 10, 13, 14, 15,
541
- 0, 12, 4, 16, 16, 3, 3, 3, 3, 16,
542
- 9, 3, 6, -1, -1, 8, 26
540
+ 3, 3, 7, 11, 12, 10, 13, 14, 15, 0,
541
+ 12, 4, 6, 16, 3, 3, 3, 3, 16, 3,
542
+ 26, -1, -1, 8, -1, -1, 9
543
543
  };
544
544
 
545
545
  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -556,16 +556,16 @@ static const yytype_uint8 yystos[] =
556
556
  static const yytype_uint8 yyr1[] =
557
557
  {
558
558
  0, 17, 18, 19, 19, 20, 20, 21, 21, 21,
559
- 22, 22, 22, 23, 23, 24, 25, 25, 25, 26,
560
- 26, 26, 26
559
+ 22, 22, 22, 23, 23, 24, 25, 25, 26, 26,
560
+ 26, 26
561
561
  };
562
562
 
563
563
  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
564
564
  static const yytype_uint8 yyr2[] =
565
565
  {
566
566
  0, 2, 4, 0, 2, 0, 2, 3, 1, 2,
567
- 3, 3, 2, 0, 2, 4, 0, 1, 3, 0,
568
- 2, 2, 5
567
+ 3, 3, 2, 0, 2, 4, 1, 3, 0, 2,
568
+ 2, 5
569
569
  };
570
570
 
571
571
 
@@ -1486,65 +1486,56 @@ yyreduce:
1486
1486
  #line 164 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1487
1487
  {
1488
1488
  rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX((yyloc).first_line), INT2FIX((yyloc).first_column)));
1489
- (yyval) = rb_funcall(__actions, rb_intern("_0_components_99914b932bd37a50b983c5e7c90ae93b"), 0);
1489
+ rb_ivar_set(__actions, rb_intern("@sequence"), rb_ary_new3(2, INT2FIX((yylsp[0]).first_line), INT2FIX((yylsp[0]).first_column)));
1490
+ (yyval) = rb_funcall(__actions, rb_intern("_0_components_2403a823f1a9854a29da7cf64f191fbe"), 1, (yyvsp[0]));
1490
1491
  }
1491
- #line 1492 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1492
+ #line 1493 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1492
1493
  break;
1493
1494
 
1494
1495
  case 17:
1495
- #line 171 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1496
+ #line 172 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1496
1497
  {
1497
1498
  rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX((yyloc).first_line), INT2FIX((yyloc).first_column)));
1499
+ rb_ivar_set(__actions, rb_intern("@sequences"), rb_ary_new3(2, INT2FIX((yylsp[-2]).first_line), INT2FIX((yylsp[-2]).first_column)));
1498
1500
  rb_ivar_set(__actions, rb_intern("@sequence"), rb_ary_new3(2, INT2FIX((yylsp[0]).first_line), INT2FIX((yylsp[0]).first_column)));
1499
- (yyval) = rb_funcall(__actions, rb_intern("_1_components_2403a823f1a9854a29da7cf64f191fbe"), 1, (yyvsp[0]));
1501
+ (yyval) = rb_funcall(__actions, rb_intern("_1_components_62da044340939f02b6c0b52917617e17"), 2, (yyvsp[-2]), (yyvsp[0]));
1500
1502
  }
1501
- #line 1502 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1503
+ #line 1504 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1502
1504
  break;
1503
1505
 
1504
1506
  case 18:
1505
- #line 179 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1507
+ #line 183 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1506
1508
  {
1507
1509
  rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX((yyloc).first_line), INT2FIX((yyloc).first_column)));
1508
- rb_ivar_set(__actions, rb_intern("@sequences"), rb_ary_new3(2, INT2FIX((yylsp[-2]).first_line), INT2FIX((yylsp[-2]).first_column)));
1509
- rb_ivar_set(__actions, rb_intern("@sequence"), rb_ary_new3(2, INT2FIX((yylsp[0]).first_line), INT2FIX((yylsp[0]).first_column)));
1510
- (yyval) = rb_funcall(__actions, rb_intern("_2_components_62da044340939f02b6c0b52917617e17"), 2, (yyvsp[-2]), (yyvsp[0]));
1510
+ (yyval) = rb_funcall(__actions, rb_intern("_0_sequence_99914b932bd37a50b983c5e7c90ae93b"), 0);
1511
1511
  }
1512
1512
  #line 1513 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1513
1513
  break;
1514
1514
 
1515
1515
  case 19:
1516
1516
  #line 190 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1517
- {
1518
- rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX((yyloc).first_line), INT2FIX((yyloc).first_column)));
1519
- (yyval) = rb_funcall(__actions, rb_intern("_0_sequence_99914b932bd37a50b983c5e7c90ae93b"), 0);
1520
- }
1521
- #line 1522 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1522
- break;
1523
-
1524
- case 20:
1525
- #line 197 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1526
1517
  {
1527
1518
  rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX((yyloc).first_line), INT2FIX((yyloc).first_column)));
1528
1519
  rb_ivar_set(__actions, rb_intern("@sequence"), rb_ary_new3(2, INT2FIX((yylsp[-1]).first_line), INT2FIX((yylsp[-1]).first_column)));
1529
1520
  rb_ivar_set(__actions, rb_intern("@code"), rb_ary_new3(2, INT2FIX((yylsp[0]).first_line), INT2FIX((yylsp[0]).first_column)));
1530
1521
  (yyval) = rb_funcall(__actions, rb_intern("_1_sequence_512ceffccf6bb7565046f90d6d7762ad"), 2, (yyvsp[-1]), (yyvsp[0]));
1531
1522
  }
1532
- #line 1533 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1523
+ #line 1524 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1533
1524
  break;
1534
1525
 
1535
- case 21:
1536
- #line 206 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1526
+ case 20:
1527
+ #line 199 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1537
1528
  {
1538
1529
  rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX((yyloc).first_line), INT2FIX((yyloc).first_column)));
1539
1530
  rb_ivar_set(__actions, rb_intern("@sequence"), rb_ary_new3(2, INT2FIX((yylsp[-1]).first_line), INT2FIX((yylsp[-1]).first_column)));
1540
1531
  rb_ivar_set(__actions, rb_intern("@follower"), rb_ary_new3(2, INT2FIX((yylsp[0]).first_line), INT2FIX((yylsp[0]).first_column)));
1541
1532
  (yyval) = rb_funcall(__actions, rb_intern("_2_sequence_4b2903c3aeb37d22d413a53653d0df28"), 2, (yyvsp[-1]), (yyvsp[0]));
1542
1533
  }
1543
- #line 1544 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1534
+ #line 1535 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1544
1535
  break;
1545
1536
 
1546
- case 22:
1547
- #line 215 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1537
+ case 21:
1538
+ #line 208 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1661 */
1548
1539
  {
1549
1540
  rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX((yyloc).first_line), INT2FIX((yyloc).first_column)));
1550
1541
  rb_ivar_set(__actions, rb_intern("@sequence"), rb_ary_new3(2, INT2FIX((yylsp[-4]).first_line), INT2FIX((yylsp[-4]).first_column)));
@@ -1552,11 +1543,11 @@ yyreduce:
1552
1543
  rb_ivar_set(__actions, rb_intern("@tag"), rb_ary_new3(2, INT2FIX((yylsp[-1]).first_line), INT2FIX((yylsp[-1]).first_column)));
1553
1544
  (yyval) = rb_funcall(__actions, rb_intern("_3_sequence_68f2380aa0f3a7de0fb9b3482705a54c"), 3, (yyvsp[-4]), (yyvsp[-3]), (yyvsp[-1]));
1554
1545
  }
1555
- #line 1556 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1546
+ #line 1547 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1556
1547
  break;
1557
1548
 
1558
1549
 
1559
- #line 1560 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1550
+ #line 1551 "../../../../ext/bison_parser/bison_parser.c" /* yacc.c:1661 */
1560
1551
  default: break;
1561
1552
  }
1562
1553
  /* User semantic actions sometimes alter yychar, and that requires
@@ -1791,7 +1782,7 @@ yyreturn:
1791
1782
  #endif
1792
1783
  return yyresult;
1793
1784
  }
1794
- #line 226 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1906 */
1785
+ #line 219 "../../../../ext/bison_parser/bison_parser.y" /* yacc.c:1906 */
1795
1786
 
1796
1787
 
1797
1788
  static VALUE cBisonParser;
@@ -160,18 +160,11 @@ grammar_rule:
160
160
  ;
161
161
 
162
162
  components:
163
-
164
- {
165
- rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX(@$.first_line), INT2FIX(@$.first_column)));
166
- $$ = rb_funcall(__actions, rb_intern("_0_components_99914b932bd37a50b983c5e7c90ae93b"), 0);
167
- }
168
-
169
- |
170
163
  sequence
171
164
  {
172
165
  rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX(@$.first_line), INT2FIX(@$.first_column)));
173
166
  rb_ivar_set(__actions, rb_intern("@sequence"), rb_ary_new3(2, INT2FIX(@1.first_line), INT2FIX(@1.first_column)));
174
- $$ = rb_funcall(__actions, rb_intern("_1_components_2403a823f1a9854a29da7cf64f191fbe"), 1, $1);
167
+ $$ = rb_funcall(__actions, rb_intern("_0_components_2403a823f1a9854a29da7cf64f191fbe"), 1, $1);
175
168
  }
176
169
 
177
170
  |
@@ -180,7 +173,7 @@ components:
180
173
  rb_ivar_set(__actions, rb_intern("@_"), rb_ary_new3(2, INT2FIX(@$.first_line), INT2FIX(@$.first_column)));
181
174
  rb_ivar_set(__actions, rb_intern("@sequences"), rb_ary_new3(2, INT2FIX(@1.first_line), INT2FIX(@1.first_column)));
182
175
  rb_ivar_set(__actions, rb_intern("@sequence"), rb_ary_new3(2, INT2FIX(@3.first_line), INT2FIX(@3.first_column)));
183
- $$ = rb_funcall(__actions, rb_intern("_2_components_62da044340939f02b6c0b52917617e17"), 2, $1, $3);
176
+ $$ = rb_funcall(__actions, rb_intern("_1_components_62da044340939f02b6c0b52917617e17"), 2, $1, $3);
184
177
  }
185
178
 
186
179
  ;
@@ -1,9 +1,14 @@
1
1
  require 'mkmf'
2
+ require 'shellwords'
2
3
 
3
4
  output = "#{File.dirname(__FILE__)}/bison_parser.c"
4
5
  bison_file = "#{File.dirname(__FILE__)}/bison_parser.y"
5
6
 
6
7
  bison = find_executable(ENV['BISON_PATH'] || 'bison')
8
+ bison_version = `#{Shellwords.shellescape(bison)} --version`.lines[0]
9
+ if bison_version =~ / [012]\.\d+(\.\d+)?\b/
10
+ abort("bison version must be >= 3.0.0")
11
+ end
7
12
  system(bison, '-o', output, bison_file) or abort("bison command failed")
8
13
 
9
14
  create_makefile 'bison_parser/bison_parser'
data/lib/bison/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Bison
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
data/lib/bison_parser.rb CHANGED
@@ -12,19 +12,7 @@ class BisonParser
12
12
  return Tokens::ACTIONS
13
13
  end
14
14
 
15
- # skip space
16
- while true
17
- while (c = self.read) && c =~ /\s/
18
- end
19
-
20
- if c == '#'
21
- while (char = self.read) && char != "\n"
22
- end
23
- else
24
- break
25
- end
26
- end
27
-
15
+ c = read_over_whitespace(line_comment_prefix: '#')
28
16
  return nil unless c
29
17
 
30
18
  case c
@@ -54,15 +54,11 @@ class BisonParser
54
54
  Bison::Rule.new(name, components).tap{ |r| r.location = @name }
55
55
  end
56
56
 
57
- def _0_components_99914b932bd37a50b983c5e7c90ae93b()
58
- []
59
- end
60
-
61
- def _1_components_2403a823f1a9854a29da7cf64f191fbe(sequence)
57
+ def _0_components_2403a823f1a9854a29da7cf64f191fbe(sequence)
62
58
  [sequence]
63
59
  end
64
60
 
65
- def _2_components_62da044340939f02b6c0b52917617e17(sequences, sequence)
61
+ def _1_components_62da044340939f02b6c0b52917617e17(sequences, sequence)
66
62
  sequences << sequence
67
63
  end
68
64
 
@@ -1,3 +1,5 @@
1
+ require 'stringio'
2
+
1
3
  class BisonParser
2
4
  attr_reader :io
3
5
  attr_accessor :lex_value, :token_row, :token_col, :row, :col
@@ -6,12 +8,34 @@ class BisonParser
6
8
  module Base
7
9
  def initialize(io)
8
10
  if String === io
9
- io = ::File.open(io, 'r')
11
+ io = StringIO.new(io)
10
12
  end
11
13
  @source = io.respond_to?(:path) ? io.path : nil
12
14
  @io, @row, @col = io, 1, 0
13
15
  end
14
16
 
17
+ def read_over_whitespace(line_comment_prefix: nil)
18
+ while true
19
+ while (c = self.read) && c =~ /\s/
20
+ end
21
+
22
+ if line_comment_prefix && c == line_comment_prefix
23
+ while (char = self.read) && char != "\n"
24
+ end
25
+ else
26
+ break
27
+ end
28
+ end
29
+ c
30
+ end
31
+
32
+ def read_integer(number='')
33
+ while (c = self.peak) && ('0'..'9').include?(c)
34
+ number << self.read
35
+ end
36
+ number
37
+ end
38
+
15
39
  def read
16
40
  io.read(1).tap do |c|
17
41
  if c == "\n"
@@ -1,3 +1,5 @@
1
+ require 'stringio'
2
+
1
3
  class <%= name %>
2
4
  attr_reader :io
3
5
  attr_accessor :lex_value, :token_row, :token_col, :row, :col
@@ -6,12 +8,34 @@ class <%= name %>
6
8
  module Base
7
9
  def initialize(io)
8
10
  if String === io
9
- io = ::File.open(io, 'r')
11
+ io = StringIO.new(io)
10
12
  end
11
13
  @source = io.respond_to?(:path) ? io.path : nil
12
14
  @io, @row, @col = io, 1, 0
13
15
  end
14
16
 
17
+ def read_over_whitespace(line_comment_prefix: nil)
18
+ while true
19
+ while (c = self.read) && c =~ /\s/
20
+ end
21
+
22
+ if line_comment_prefix && c == line_comment_prefix
23
+ while (char = self.read) && char != "\n"
24
+ end
25
+ else
26
+ break
27
+ end
28
+ end
29
+ c
30
+ end
31
+
32
+ def read_integer(number='')
33
+ while (c = self.peak) && ('0'..'9').include?(c)
34
+ number << self.read
35
+ end
36
+ number
37
+ end
38
+
15
39
  def read
16
40
  io.read(1).tap do |c|
17
41
  if c == "\n"
@@ -1,9 +1,14 @@
1
1
  require 'mkmf'
2
+ require 'shellwords'
2
3
 
3
4
  output = "#{File.dirname(__FILE__)}/<%= uname %>.c"
4
5
  bison_file = "#{File.dirname(__FILE__)}/<%= uname %>.y"
5
6
 
6
7
  bison = find_executable(ENV['BISON_PATH'] || 'bison')
8
+ bison_version = `#{Shellwords.shellescape(bison)} --version`.lines[0]
9
+ if bison_version =~ / [012]\.\d+(\.\d+)?\b/
10
+ abort("bison version must be >= 3.0.0")
11
+ end
7
12
  system(bison, '-o', output, bison_file) or abort("bison command failed")
8
13
 
9
14
  create_makefile '<%= uname %>/<%= uname %>'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mkbison
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Woo
@@ -82,6 +82,9 @@ files:
82
82
  - Rakefile
83
83
  - bin/mkbison
84
84
  - bison_parser.rby
85
+ - examples/arithmetic/Gemfile
86
+ - examples/arithmetic/Rakefile
87
+ - examples/arithmetic/arithmetic.rby
85
88
  - ext/bison_parser/bison_parser.c
86
89
  - ext/bison_parser/bison_parser.y
87
90
  - ext/bison_parser/extconf.rb