lrama 0.5.1 → 0.5.3

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
  SHA256:
3
- metadata.gz: 20a0927bedeb14281abb8a5c59daf643fdfe556b5899cbe4872878b022804da2
4
- data.tar.gz: 731fdd0201266db9724a2ebcc1162427a2cfaa9d0d94543e1298b3f2683eb14f
3
+ metadata.gz: 32eaf486545ca4143a227a34cee2bfdb94928e002a85fcb2e098dba3dedb71c7
4
+ data.tar.gz: b80a7402d9f6caf9f0e8b5396e4bd6b80d84487a35c8cd4b4d711e51ffb56601
5
5
  SHA512:
6
- metadata.gz: 3a6e7c0ef4e7266dae41dba15e3a5d7609cb7171b82e0dbd5b75595e8e3cf8a4a402c5b710cc0f714c54357ef9fc20fd0935e55b8c529c99cd3c09ea173efb87
7
- data.tar.gz: fa867c9be43384c7f282bf22ecd2b0939cd0dca263a51914871dba42f409ddc01fb00c34d8696288c3668177fdc450ff1bc9fb5e90fdf053e2d56a5bf31bbe04
6
+ metadata.gz: 1d118074af8984d85e27485a0c9fb2f8c7eab9a55b771ea3eff17e26d84fe56316404f6316ba5a9c83e61591c83ff9048c6625a904529aa686417f6f295499d9
7
+ data.tar.gz: e3591cc5f70e6fe8a04af5070a7b5d6ee60e98718c4c6dc6db1fbef2b3be9f5239155da91bb51ba10611b5017925f1bf71aa1259fd5550b5af6d0ba458e2ab96
@@ -35,6 +35,7 @@ jobs:
35
35
  ruby-version: ${{ matrix.ruby }}
36
36
  bundler-cache: true
37
37
  - run: bundle install
38
+ - run: bundle exec rbs collection install
38
39
  - run: bundle exec steep check
39
40
  test-ruby:
40
41
  runs-on: ubuntu-20.04
@@ -57,9 +58,7 @@ jobs:
57
58
  - run: mkdir -p tool/lrama
58
59
  working-directory: ../ruby
59
60
  - name: Copy Lrama to ruby/tool
60
- run: cp -r exe lib ../ruby/tool/lrama
61
- # TODO: Consider how to manage changes on ruby/ruby master and ruby/lrama
62
- # run: cp -r exe lib template ../ruby/tool/lrama
61
+ run: cp -r exe lib template ../ruby/tool/lrama
63
62
  working-directory:
64
63
  - run: tree tool/lrama
65
64
  working-directory: ../ruby
data/.gitignore CHANGED
@@ -1,4 +1,6 @@
1
+ /.gem_rbs_collection/
1
2
  /tmp
2
3
  .irbrc
3
4
  /Gemfile.lock
4
5
  /pkg/
6
+ coverage/
data/Gemfile CHANGED
@@ -8,3 +8,4 @@ gem "stackprof"
8
8
  gem "rake"
9
9
  gem "rbs", require: false
10
10
  gem "steep", require: false
11
+ gem "simplecov", require: false
data/LEGAL.md CHANGED
@@ -5,22 +5,7 @@ mentioned below.
5
5
 
6
6
  ## GNU General Public License version 3
7
7
 
8
- These files are licensed under the GNU General Public License version 3. See these files for more information.
8
+ These files are licensed under the GNU General Public License version 3 or later. See these files for more information.
9
9
 
10
10
  * template/bison/yacc.c
11
11
  * template/bison/yacc.h
12
-
13
- ## Same with Ruby
14
-
15
- These files are licensed same with Ruby. See https://github.com/ruby/ruby/blob/master/COPYING for more information.
16
-
17
- * spec/fixtures/integration/ruby_3_0_5/parse.tmp.y
18
- * spec/fixtures/integration/ruby_3_0_5/y.tab.c
19
- * spec/fixtures/integration/ruby_3_0_5/y.tab.h
20
- * spec/fixtures/integration/ruby_3_1_0/parse.tmp.y
21
- * spec/fixtures/integration/ruby_3_1_0/y.tab.c
22
- * spec/fixtures/integration/ruby_3_1_0/y.tab.h
23
- * spec/fixtures/integration/ruby_3_2_0/parse.tmp.y
24
- * spec/fixtures/integration/ruby_3_2_0/y.tab.c
25
- * spec/fixtures/integration/ruby_3_2_0/y.tab.h
26
-
data/README.md CHANGED
@@ -62,7 +62,7 @@ This branch generates "parse.c" compatible with Bison 3.8.2 for ruby 3.0, 3.1, 3
62
62
 
63
63
  1. Update `Lrama::VERSION`
64
64
  2. Release as a gem by `rake release`
65
- 3. Update Lrama in ruby/ruby by `cp -r exe lib ruby/tool/lrama`
65
+ 3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib ruby/tool/lrama`
66
66
  4. Create new release on [GitHub](https://github.com/ruby/lrama/releases)
67
67
 
68
68
  ## License
data/Steepfile CHANGED
@@ -4,4 +4,7 @@ target :lib do
4
4
  signature "sig"
5
5
 
6
6
  check "lib/lrama/bitmap.rb"
7
+ check "lib/lrama/report/duration.rb"
8
+ check "lib/lrama/report/profile.rb"
9
+ check "lib/lrama/warning.rb"
7
10
  end
data/doc/TODO.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # TODO
2
2
 
3
3
  * command
4
- * [ ] Add "--bison" option
5
4
  * lexer
6
5
  * [x] Basic functionalities
7
6
  * parser
@@ -27,7 +26,7 @@
27
26
  * [x] Table compaction
28
27
  * [x] -d option
29
28
  * yacc.c
30
- * [ ] %lex-param
29
+ * [x] %lex-param
31
30
  * [x] %parse-param
32
31
  * [x] %printer
33
32
  * [x] Replace $, @ in user codes
@@ -46,7 +45,9 @@
46
45
  * [ ] Bison style
47
46
  * [ ] Wrap not selected reduce with "[]". See basic.output file generated by Bison.
48
47
  * Error Tolerance
49
- * [x] Subset of Corchuelo et al.
48
+ * [x] Corchuelo et al. algorithm with N = 1 (this means the next token when error is raised)
49
+ * [x] Add new decl for error token semantic value initialization (%error-token)
50
+ * [ ] Use YYMALLOC & YYFREE
50
51
  * Lex state
51
52
  * CI
52
53
  * [x] Setup CI
data/exe/lrama CHANGED
@@ -4,4 +4,4 @@
4
4
  $LOAD_PATH << File.join(__dir__, "../lib")
5
5
  require "lrama"
6
6
 
7
- Lrama::Command.new.run(ARGV.dup)
7
+ Lrama::Command.new(ARGV.dup).run
data/lib/lrama/command.rb CHANGED
@@ -2,94 +2,57 @@ require 'optparse'
2
2
 
3
3
  module Lrama
4
4
  class Command
5
- def run(argv)
6
- opt = OptionParser.new
7
-
8
- # opt.on('-h') {|v| p v }
9
- opt.on('-V', '--version') {|v| puts Lrama::VERSION ; exit 0 }
10
-
11
- # Tuning the Parser
12
- skeleton = "bison/yacc.c"
13
-
14
- opt.on('-S', '--skeleton=FILE') {|v| skeleton = v }
15
- opt.on('-t') { } # Do nothing
16
-
17
- # Output Files:
18
- header = false
19
- header_file = nil
20
- report = []
21
- report_file = nil
22
- outfile = "y.tab.c"
23
-
24
- opt.on('-h', '--header=[FILE]') {|v| header = true; header_file = v }
25
- opt.on('-d') { header = true }
26
- opt.on('-r', '--report=THINGS') {|v| report = v.split(',') }
27
- opt.on('--report-file=FILE') {|v| report_file = v }
28
- opt.on('-v') { } # Do nothing
29
- opt.on('-o', '--output=FILE') {|v| outfile = v }
30
-
31
- # Hidden
32
- trace = []
33
- opt.on('--trace=THINGS') {|v| trace = v.split(',') }
34
-
35
- # Error Recovery
36
- error_recovery = false
37
- opt.on('-e') {|v| error_recovery = true }
38
-
39
- opt.parse!(argv)
40
-
41
- trace_opts = validate_trace(trace)
42
- report_opts = validate_report(report)
43
-
44
- grammar_file = argv.shift
45
-
46
- if !report.empty? && report_file.nil? && grammar_file
47
- report_file = File.dirname(grammar_file) + "/" + File.basename(grammar_file, ".*") + ".output"
48
- end
5
+ def initialize(argv)
6
+ @argv = argv
7
+
8
+ @version = nil
9
+ @skeleton = "bison/yacc.c"
10
+ @header = false
11
+ @header_file = nil
12
+ @report = []
13
+ @report_file = nil
14
+ @outfile = "y.tab.c"
15
+ @trace = []
16
+ @error_recovery = false
17
+ @grammar_file = nil
18
+ @report_file = nil
19
+ @trace_opts = nil
20
+ @report_opts = nil
21
+ end
49
22
 
50
- if !header_file && header
51
- case
52
- when outfile
53
- header_file = File.dirname(outfile) + "/" + File.basename(outfile, ".*") + ".h"
54
- when grammar_file
55
- header_file = File.dirname(grammar_file) + "/" + File.basename(grammar_file, ".*") + ".h"
56
- end
57
- end
23
+ def run
24
+ parse_option
58
25
 
59
- if !grammar_file
60
- abort "File should be specified\n"
26
+ if @version
27
+ puts Lrama::VERSION
28
+ exit 0
61
29
  end
62
30
 
63
- Report::Duration.enable if trace_opts[:time]
31
+ Report::Duration.enable if @trace_opts[:time]
64
32
 
65
33
  warning = Lrama::Warning.new
66
- if grammar_file == '-'
67
- grammar_file = argv.shift or abort "File name for STDIN should be specified\n"
68
- y = STDIN.read
69
- else
70
- y = File.read(grammar_file)
71
- end
72
- grammar = Lrama::Parser.new(y).parse
73
- states = Lrama::States.new(grammar, warning, trace_state: (trace_opts[:automaton] || trace_opts[:closure]))
34
+ grammar = Lrama::Parser.new(@y.read).parse
35
+ states = Lrama::States.new(grammar, warning, trace_state: (@trace_opts[:automaton] || @trace_opts[:closure]))
74
36
  states.compute
75
37
  context = Lrama::Context.new(states)
76
38
 
77
- if report_file
39
+ if @report_file
78
40
  reporter = Lrama::StatesReporter.new(states)
79
- File.open(report_file, "w+") do |f|
80
- reporter.report(f, **report_opts)
41
+ File.open(@report_file, "w+") do |f|
42
+ reporter.report(f, **@report_opts)
81
43
  end
82
44
  end
83
45
 
84
- File.open(outfile, "w+") do |f|
46
+ File.open(@outfile, "w+") do |f|
85
47
  Lrama::Output.new(
86
48
  out: f,
87
- output_file_path: outfile,
88
- template_name: skeleton,
89
- grammar_file_path: grammar_file,
90
- header_file_path: header_file,
49
+ output_file_path: @outfile,
50
+ template_name: @skeleton,
51
+ grammar_file_path: @grammar_file,
52
+ header_file_path: @header_file,
91
53
  context: context,
92
54
  grammar: grammar,
55
+ error_recovery: @error_recovery,
93
56
  ).render
94
57
  end
95
58
 
@@ -144,5 +107,61 @@ module Lrama
144
107
 
145
108
  return h
146
109
  end
110
+
111
+ def parse_option
112
+ opt = OptionParser.new
113
+
114
+ # opt.on('-h') {|v| p v }
115
+ opt.on('-V', '--version') {|v| @version = true }
116
+
117
+ # Tuning the Parser
118
+ opt.on('-S', '--skeleton=FILE') {|v| @skeleton = v }
119
+ opt.on('-t') { } # Do nothing
120
+
121
+ # Output Files:
122
+ opt.on('-h', '--header=[FILE]') {|v| @header = true; @header_file = v }
123
+ opt.on('-d') { @header = true }
124
+ opt.on('-r', '--report=THINGS') {|v| @report = v.split(',') }
125
+ opt.on('--report-file=FILE') {|v| @report_file = v }
126
+ opt.on('-v') { } # Do nothing
127
+ opt.on('-o', '--output=FILE') {|v| @outfile = v }
128
+
129
+ # Hidden
130
+ opt.on('--trace=THINGS') {|v| @trace = v.split(',') }
131
+
132
+ # Error Recovery
133
+ opt.on('-e') {|v| @error_recovery = true }
134
+
135
+ opt.parse!(@argv)
136
+
137
+ @trace_opts = validate_trace(@trace)
138
+ @report_opts = validate_report(@report)
139
+
140
+ @grammar_file = @argv.shift
141
+
142
+ if !@grammar_file
143
+ abort "File should be specified\n"
144
+ end
145
+
146
+ if @grammar_file == '-'
147
+ @grammar_file = @argv.shift or abort "File name for STDIN should be specified\n"
148
+ @y = STDIN
149
+ else
150
+ @y = File.open(@grammar_file, 'r')
151
+ end
152
+
153
+ if !@report.empty? && @report_file.nil? && @grammar_file
154
+ @report_file = File.dirname(@grammar_file) + "/" + File.basename(@grammar_file, ".*") + ".output"
155
+ end
156
+
157
+ if !@header_file && @header
158
+ case
159
+ when @outfile
160
+ @header_file = File.dirname(@outfile) + "/" + File.basename(@outfile, ".*") + ".h"
161
+ when @grammar_file
162
+ @header_file = File.dirname(@grammar_file) + "/" + File.basename(@grammar_file, ".*") + ".h"
163
+ end
164
+ end
165
+ end
147
166
  end
148
167
  end
data/lib/lrama/context.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "lrama/report"
1
+ require "lrama/report/duration"
2
2
 
3
3
  module Lrama
4
4
  # This is passed to a template
@@ -89,6 +89,16 @@ module Lrama
89
89
  return a
90
90
  end
91
91
 
92
+ def yytranslate_inverted
93
+ a = Array.new(@states.symbols.count, @states.undef_symbol.token_id)
94
+
95
+ @states.terms.each do |term|
96
+ a[term.number] = term.token_id
97
+ end
98
+
99
+ return a
100
+ end
101
+
92
102
  # Mapping from rule number to line number of the rule is defined.
93
103
  # Dummy rule is appended as the first element whose value is 0
94
104
  # because 0 means error in yydefact.
@@ -0,0 +1,123 @@
1
+ require "forwardable"
2
+
3
+ module Lrama
4
+ class Grammar
5
+ class Code < Struct.new(:type, :token_code, keyword_init: true)
6
+ extend Forwardable
7
+
8
+ def_delegators "token_code", :s_value, :line, :column, :references
9
+
10
+ # $$, $n, @$, @n is translated to C code
11
+ def translated_code
12
+ case type
13
+ when :user_code
14
+ translated_user_code
15
+ when :initial_action
16
+ translated_initial_action_code
17
+ end
18
+ end
19
+
20
+ # * ($1) error
21
+ # * ($$) *yyvaluep
22
+ # * (@1) error
23
+ # * (@$) *yylocationp
24
+ def translated_printer_code(tag)
25
+ t_code = s_value.dup
26
+
27
+ references.reverse.each do |ref|
28
+ first_column = ref.first_column
29
+ last_column = ref.last_column
30
+
31
+ case
32
+ when ref.value == "$" && ref.type == :dollar # $$
33
+ # Omit "<>"
34
+ member = tag.s_value[1..-2]
35
+ str = "((*yyvaluep).#{member})"
36
+ when ref.value == "$" && ref.type == :at # @$
37
+ str = "(*yylocationp)"
38
+ when ref.type == :dollar # $n
39
+ raise "$#{ref.value} can not be used in %printer."
40
+ when ref.type == :at # @n
41
+ raise "@#{ref.value} can not be used in %printer."
42
+ else
43
+ raise "Unexpected. #{self}, #{ref}"
44
+ end
45
+
46
+ t_code[first_column..last_column] = str
47
+ end
48
+
49
+ return t_code
50
+ end
51
+ alias :translated_error_token_code :translated_printer_code
52
+
53
+
54
+ private
55
+
56
+ # * ($1) yyvsp[i]
57
+ # * ($$) yyval
58
+ # * (@1) yylsp[i]
59
+ # * (@$) yyloc
60
+ def translated_user_code
61
+ t_code = s_value.dup
62
+
63
+ references.reverse.each do |ref|
64
+ first_column = ref.first_column
65
+ last_column = ref.last_column
66
+
67
+ case
68
+ when ref.value == "$" && ref.type == :dollar # $$
69
+ # Omit "<>"
70
+ member = ref.tag.s_value[1..-2]
71
+ str = "(yyval.#{member})"
72
+ when ref.value == "$" && ref.type == :at # @$
73
+ str = "(yyloc)"
74
+ when ref.type == :dollar # $n
75
+ i = -ref.position_in_rhs + ref.value
76
+ # Omit "<>"
77
+ member = ref.tag.s_value[1..-2]
78
+ str = "(yyvsp[#{i}].#{member})"
79
+ when ref.type == :at # @n
80
+ i = -ref.position_in_rhs + ref.value
81
+ str = "(yylsp[#{i}])"
82
+ else
83
+ raise "Unexpected. #{self}, #{ref}"
84
+ end
85
+
86
+ t_code[first_column..last_column] = str
87
+ end
88
+
89
+ return t_code
90
+ end
91
+
92
+ # * ($1) error
93
+ # * ($$) yylval
94
+ # * (@1) error
95
+ # * (@$) yylloc
96
+ def translated_initial_action_code
97
+ t_code = s_value.dup
98
+
99
+ references.reverse.each do |ref|
100
+ first_column = ref.first_column
101
+ last_column = ref.last_column
102
+
103
+ case
104
+ when ref.value == "$" && ref.type == :dollar # $$
105
+ str = "yylval"
106
+ when ref.value == "$" && ref.type == :at # @$
107
+ str = "yylloc"
108
+ when ref.type == :dollar # $n
109
+ raise "$#{ref.value} can not be used in initial_action."
110
+ when ref.type == :at # @n
111
+ raise "@#{ref.value} can not be used in initial_action."
112
+ else
113
+ raise "Unexpected. #{self}, #{ref}"
114
+ end
115
+
116
+ t_code[first_column..last_column] = str
117
+ end
118
+
119
+ return t_code
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,9 @@
1
+ module Lrama
2
+ class Grammar
3
+ class ErrorToken < Struct.new(:ident_or_tags, :code, :lineno, keyword_init: true)
4
+ def translated_code(member)
5
+ code.translated_error_token_code(member)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Lrama
2
+ class Grammar
3
+ class Precedence < Struct.new(:type, :precedence, keyword_init: true)
4
+ include Comparable
5
+
6
+ def <=>(other)
7
+ self.precedence <=> other.precedence
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Lrama
2
+ class Grammar
3
+ class Printer < Struct.new(:ident_or_tags, :code, :lineno, keyword_init: true)
4
+ def translated_code(member)
5
+ code.translated_printer_code(member)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ # type: :dollar or :at
2
+ # ex_tag: "$<tag>1" (Optional)
3
+
4
+ module Lrama
5
+ class Grammar
6
+ class Reference < Struct.new(:type, :value, :ex_tag, :first_column, :last_column, :referring_symbol, :position_in_rhs, keyword_init: true)
7
+ def tag
8
+ if ex_tag
9
+ ex_tag
10
+ else
11
+ # FIXME: Remove this class check
12
+ if referring_symbol.is_a?(Symbol)
13
+ referring_symbol.tag
14
+ else
15
+ # Lrama::Lexer::Token (User_code) case
16
+ nil
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ module Lrama
2
+ class Grammar
3
+ class Rule < Struct.new(:id, :lhs, :rhs, :code, :nullable, :precedence_sym, :lineno, keyword_init: true)
4
+ # TODO: Change this to display_name
5
+ def to_s
6
+ l = lhs.id.s_value
7
+ r = rhs.empty? ? "ε" : rhs.map {|r| r.id.s_value }.join(", ")
8
+
9
+ "#{l} -> #{r}"
10
+ end
11
+
12
+ # Used by #user_actions
13
+ def as_comment
14
+ l = lhs.id.s_value
15
+ r = rhs.empty? ? "%empty" : rhs.map(&:display_name).join(" ")
16
+
17
+ "#{l}: #{r}"
18
+ end
19
+
20
+ def precedence
21
+ precedence_sym&.precedence
22
+ end
23
+
24
+ def initial_rule?
25
+ id == 0
26
+ end
27
+
28
+ def translated_code
29
+ code&.translated_code
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,94 @@
1
+ # Symbol is both of nterm and term
2
+ # `number` is both for nterm and term
3
+ # `token_id` is tokentype for term, internal sequence number for nterm
4
+ #
5
+ # TODO: Add validation for ASCII code range for Token::Char
6
+
7
+ module Lrama
8
+ class Grammar
9
+ class Symbol < Struct.new(:id, :alias_name, :number, :tag, :term, :token_id, :nullable, :precedence, :printer, :error_token, keyword_init: true)
10
+ attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol
11
+
12
+ def term?
13
+ term
14
+ end
15
+
16
+ def nterm?
17
+ !term
18
+ end
19
+
20
+ def eof_symbol?
21
+ !!@eof_symbol
22
+ end
23
+
24
+ def error_symbol?
25
+ !!@error_symbol
26
+ end
27
+
28
+ def undef_symbol?
29
+ !!@undef_symbol
30
+ end
31
+
32
+ def accept_symbol?
33
+ !!@accept_symbol
34
+ end
35
+
36
+ def display_name
37
+ if alias_name
38
+ alias_name
39
+ else
40
+ id.s_value
41
+ end
42
+ end
43
+
44
+ # name for yysymbol_kind_t
45
+ #
46
+ # See: b4_symbol_kind_base
47
+ def enum_name
48
+ case
49
+ when accept_symbol?
50
+ name = "YYACCEPT"
51
+ when eof_symbol?
52
+ name = "YYEOF"
53
+ when term? && id.type == Token::Char
54
+ if alias_name
55
+ name = number.to_s + alias_name
56
+ else
57
+ name = number.to_s + id.s_value
58
+ end
59
+ when term? && id.type == Token::Ident
60
+ name = id.s_value
61
+ when nterm? && (id.s_value.include?("$") || id.s_value.include?("@"))
62
+ name = number.to_s + id.s_value
63
+ when nterm?
64
+ name = id.s_value
65
+ else
66
+ raise "Unexpected #{self}"
67
+ end
68
+
69
+ "YYSYMBOL_" + name.gsub(/[^a-zA-Z_0-9]+/, "_")
70
+ end
71
+
72
+ # comment for yysymbol_kind_t
73
+ def comment
74
+ case
75
+ when accept_symbol?
76
+ # YYSYMBOL_YYACCEPT
77
+ id.s_value
78
+ when eof_symbol?
79
+ # YYEOF
80
+ alias_name
81
+ when (term? && 0 < token_id && token_id < 128)
82
+ # YYSYMBOL_3_backslash_, YYSYMBOL_14_
83
+ alias_name || id.s_value
84
+ when id.s_value.include?("$") || id.s_value.include?("@")
85
+ # YYSYMBOL_21_1
86
+ id.s_value
87
+ else
88
+ # YYSYMBOL_keyword_class, YYSYMBOL_strings_1
89
+ alias_name || id.s_value
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,10 @@
1
+ module Lrama
2
+ class Grammar
3
+ class Union < Struct.new(:code, :lineno, keyword_init: true)
4
+ def braces_less_code
5
+ # Remove braces
6
+ code.s_value[1..-2]
7
+ end
8
+ end
9
+ end
10
+ end