Skip to content

Commit 25226a0

Browse files
committed
wip
1 parent a49ab82 commit 25226a0

23 files changed

+1383
-404
lines changed

Steepfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ target :lib do
77
check "lib/lrama/grammar/code/printer_code.rb"
88
check "lib/lrama/grammar/code.rb"
99
check "lib/lrama/grammar/counter.rb"
10+
check "lib/lrama/grammar/parser_state.rb"
1011
check "lib/lrama/grammar/percent_code.rb"
1112
check "lib/lrama/grammar/precedence.rb"
1213
check "lib/lrama/grammar/printer.rb"
@@ -15,6 +16,9 @@ target :lib do
1516
check "lib/lrama/lexer/token/char.rb"
1617
check "lib/lrama/lexer/token/ident.rb"
1718
check "lib/lrama/lexer/token/parameterizing.rb"
19+
check "lib/lrama/lexer/token/parser_state_pop.rb"
20+
check "lib/lrama/lexer/token/parser_state_push.rb"
21+
check "lib/lrama/lexer/token/parser_state_set.rb"
1822
check "lib/lrama/lexer/token/tag.rb"
1923
check "lib/lrama/lexer/token/user_code.rb"
2024
check "lib/lrama/lexer/location.rb"

lib/lrama/grammar.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require "lrama/grammar/code"
33
require "lrama/grammar/counter"
44
require "lrama/grammar/error_token"
5+
require "lrama/grammar/parser_state"
56
require "lrama/grammar/percent_code"
67
require "lrama/grammar/precedence"
78
require "lrama/grammar/printer"
@@ -16,7 +17,7 @@
1617
module Lrama
1718
# Grammar is the result of parsing an input grammar file
1819
class Grammar
19-
attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux
20+
attr_reader :percent_codes, :parser_states, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux
2021
attr_accessor :union, :expect,
2122
:printers, :error_tokens,
2223
:lex_param, :parse_param, :initial_action,
@@ -31,6 +32,7 @@ def initialize(rule_counter)
3132
@percent_codes = []
3233
@printers = []
3334
@error_tokens = []
35+
@parser_states = []
3436
@symbols = []
3537
@types = []
3638
@rule_builders = []
@@ -58,6 +60,10 @@ def add_error_token(ident_or_tags:, token_code:, lineno:)
5860
@error_tokens << ErrorToken.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
5961
end
6062

63+
def add_parser_state(state_id, state_list)
64+
@parser_states << ParserState.new(state_id: state_id, state_list: state_list)
65+
end
66+
6167
def add_term(id:, alias_name: nil, tag: nil, token_id: nil, replace: false)
6268
if token_id && (sym = @symbols.find {|s| s.token_id == token_id })
6369
if replace
@@ -186,7 +192,7 @@ def find_symbol_by_id(id)
186192
end
187193

188194
def find_symbol_by_id!(id)
189-
find_symbol_by_id(id) || (raise "Symbol not found: #{id}")
195+
find_symbol_by_id(id) || (raise "Symbol not found: #{id.s_value}")
190196
end
191197

192198
def find_symbol_by_number!(number)

lib/lrama/grammar/parser_state.rb

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
module Lrama
2+
class Grammar
3+
class ParserState
4+
attr_reader :state_id, :state_list
5+
6+
def initialize(state_id:, state_list:)
7+
@state_id = state_id
8+
@state_list = state_list
9+
end
10+
11+
def enum_definition
12+
<<~ENUM
13+
enum #{enum_name}
14+
{
15+
#{enum_body}
16+
};
17+
typedef enum #{enum_name} #{enum_type};
18+
19+
static const char *const #{enum_name_table_name}[] = {
20+
#{int_to_name.join(", ")}
21+
};
22+
23+
YY_ATTRIBUTE_UNUSED
24+
static const char *
25+
#{enum_name}_name (#{enum_type} num)
26+
{
27+
return #{enum_name_table_name}[num];
28+
}
29+
30+
# define #{state_name_macro}(value) #{enum_name}_name (value)
31+
# define #{current_state_name_macro} #{state_name_macro} (*#{stack_prefix}_p)
32+
ENUM
33+
end
34+
35+
def state_name_macro
36+
"YY_STATE_#{state_name.upcase}_NAME"
37+
end
38+
39+
def current_state_name_macro
40+
"YY_CURRENT_STATE_#{state_name.upcase}_NAME"
41+
end
42+
43+
def states_functions
44+
<<~FUNC
45+
# define YYPUSH_STATE_#{state_name.upcase}(value) \\
46+
do \\
47+
{ \\
48+
if (#{stack_prefix} + #{states_stack_size_name} - 1 <= #{stack_prefix}_p) \\
49+
YYSTATE_STACK_INCREASE (#{stack_prefix}_a, #{stack_prefix}, #{stack_prefix}_p, #{states_stack_size_name}, "#{state_name}"); \\
50+
YYDPRINTF ((stderr, "Push %s to #{state_name}\\n", #{state_name_macro} (value))); \\
51+
*++#{stack_prefix}_p = value; \\
52+
} \\
53+
while (0)
54+
55+
# define YYPOP_STATE_#{state_name.upcase}() \\
56+
do \\
57+
{ \\
58+
YYDPRINTF ((stderr, "Pop #{state_name}\\n")); \\
59+
if (#{stack_prefix}_p != #{stack_prefix}) \\
60+
{ \\
61+
#{stack_prefix}_p -= 1; \\
62+
} \\
63+
else \\
64+
{ \\
65+
YYDPRINTF ((stderr, "Try to pop empty #{state_name} stack\\n")); \\
66+
} \\
67+
} \\
68+
while (0)
69+
70+
# define YYSET_STATE_#{state_name.upcase}(value) \\
71+
do \\
72+
{ \\
73+
YYDPRINTF ((stderr, "Set %s to #{state_name}\\n", #{state_name_macro} (value))); \\
74+
*#{stack_prefix}_p = value; \\
75+
} \\
76+
while (0)
77+
78+
# define YY_STATE_#{state_name.upcase} #{stack_prefix}_p
79+
FUNC
80+
end
81+
82+
def states_clean_up_stack
83+
<<~CODE
84+
if (#{stack_prefix} != #{stack_prefix}_a)
85+
YYSTACK_FREE (#{stack_prefix});
86+
CODE
87+
end
88+
89+
def states_stack_size_name
90+
"#{stack_prefix}_stacksize"
91+
end
92+
93+
def states_stacks
94+
<<~STACKS
95+
/* Current size of state stack size */
96+
YYPTRDIFF_T #{states_stack_size_name} = YYINITDEPTH;
97+
98+
/* The parser state stack (#{stack_prefix}): array, bottom, top. */
99+
int #{stack_prefix}_a[YYINITDEPTH];
100+
int *#{stack_prefix} = #{stack_prefix}_a;
101+
int *#{stack_prefix}_p = #{stack_prefix};
102+
STACKS
103+
end
104+
105+
def state_name
106+
state_id.s_value
107+
end
108+
109+
def enum_name
110+
"yyparser_state_#{state_name}"
111+
end
112+
113+
def enum_type
114+
"#{enum_name}_t"
115+
end
116+
117+
def enum_body
118+
state_list.map do |state|
119+
state.s_value
120+
end.join(",\n ")
121+
end
122+
123+
def int_to_name
124+
state_list.map do |state|
125+
"\"#{state.s_value}\""
126+
end << "YY_NULLPTR"
127+
end
128+
129+
def enum_name_table_name
130+
"#{enum_name}_names"
131+
end
132+
133+
def stack_prefix
134+
"yyparser_state_#{state_name}"
135+
end
136+
end
137+
end
138+
end

lib/lrama/grammar/rule_builder.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ def process_rhs
114114
@parameterizing_rules << r
115115
end
116116
@replaced_rhs << parameterizing.build_token
117+
when Lrama::Lexer::Token::ParserStatePop
118+
process_parser_state_token(token, "parser_state_pop_", "YYPOP_STATE_#{token.s_value.upcase}();", i)
119+
when Lrama::Lexer::Token::ParserStatePush
120+
process_parser_state_token(token, "parser_state_push_", "YYPUSH_STATE_#{token.s_value.upcase}(#{token.state.s_value});", i)
121+
when Lrama::Lexer::Token::ParserStateSet
122+
process_parser_state_token(token, "parser_state_set_", "YYSET_STATE_#{token.s_value.upcase}(#{token.state.s_value});", i)
117123
when Lrama::Lexer::Token::UserCode
118124
prefix = token.referred ? "@" : "$@"
119125
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
@@ -132,6 +138,20 @@ def process_rhs
132138
end
133139
end
134140

141+
def process_parser_state_token(token, prefix, code, position_in_original_rule_rhs)
142+
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + token.s_value + @midrule_action_counter.increment.to_s)
143+
user_code = Lrama::Lexer::Token::UserCode.new(s_value: code, location: token.location)
144+
145+
@replaced_rhs << new_token
146+
rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, position_in_original_rule_rhs, skip_preprocess_references: true)
147+
rule_builder.lhs = new_token
148+
rule_builder.user_code = user_code
149+
rule_builder.complete_input
150+
rule_builder.setup_rules
151+
152+
@rule_builders_for_derived_rules << rule_builder
153+
end
154+
135155
def numberize_references
136156
# Bison n'th component is 1-origin
137157
(rhs + [user_code]).compact.each.with_index(1) do |token, i|

lib/lrama/lexer.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class Lexer
2828
%error-token
2929
%empty
3030
%code
31+
%parser-state-push
32+
%parser-state-pop
33+
%parser-state-set
34+
%parser-state
3135
)
3236

3337
def initialize(text)

lib/lrama/lexer/token.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
require 'lrama/lexer/token/char'
22
require 'lrama/lexer/token/ident'
33
require 'lrama/lexer/token/parameterizing'
4+
require 'lrama/lexer/token/parser_state_pop'
5+
require 'lrama/lexer/token/parser_state_push'
6+
require 'lrama/lexer/token/parser_state_set'
47
require 'lrama/lexer/token/tag'
58
require 'lrama/lexer/token/user_code'
69

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module Lrama
2+
class Lexer
3+
class Token
4+
class ParserStatePop < Token
5+
end
6+
end
7+
end
8+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Lrama
2+
class Lexer
3+
class Token
4+
class ParserStatePush < Token
5+
attr_accessor :state
6+
end
7+
end
8+
end
9+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Lrama
2+
class Lexer
3+
class Token
4+
class ParserStateSet < Token
5+
attr_accessor :state
6+
end
7+
end
8+
end
9+
end

lib/lrama/output.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,34 @@ def percent_code(name)
358358
end.join
359359
end
360360

361+
def has_parser_states?
362+
!@grammar.parser_states.empty?
363+
end
364+
365+
def parser_states_enums
366+
@grammar.parser_states.map do |ps|
367+
ps.enum_definition
368+
end
369+
end
370+
371+
def parser_states_stacks
372+
@grammar.parser_states.map do |ps|
373+
ps.states_stacks
374+
end
375+
end
376+
377+
def parser_states_functions
378+
@grammar.parser_states.map do |ps|
379+
ps.states_functions
380+
end
381+
end
382+
383+
def parser_states_clean_up_stack
384+
@grammar.parser_states.map do |ps|
385+
ps.states_clean_up_stack
386+
end
387+
end
388+
361389
private
362390

363391
def eval_template(file, path)

0 commit comments

Comments
 (0)