Skip to content

Commit

Permalink
Extract functions
Browse files Browse the repository at this point in the history
  • Loading branch information
yui-knk committed Nov 19, 2023
1 parent dfb3d7a commit 8412c68
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 64 deletions.
96 changes: 96 additions & 0 deletions lib/lrama/grammar/parser_state.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,106 @@ def initialize(state_id:, state_list:)
@state_list = state_list
end

def enum_definition
<<~ENUM
enum #{enum_name}
{
#{enum_body}
};
typedef enum #{enum_name} #{enum_type};
static const char *const #{enum_name_table_name}[] = {
#{int_to_name.join(", ")}
};
YY_ATTRIBUTE_UNUSED
static const char *
#{enum_name}_name (#{enum_type} num)
{
return #{enum_name_table_name}[num];
}
# define YY_STATE_#{state_name.upcase}_NAME #{enum_name}_name (*#{stack_prefix}_p)
ENUM
end

def states_functions
# TODO: Stack check for push
<<~FUNC
# define YYPUSH_STATE_#{state_name.upcase}(value) \\
do \\
{ \\
YYDPRINTF ((stderr, "Push #{state_name}\\n")); \\
*++#{stack_prefix}_p = value; \\
} \\
while (0)
# define YYPOP_STATE_#{state_name.upcase}() \\
do \\
{ \\
YYDPRINTF ((stderr, "Pop #{state_name}\\n")); \\
if (#{stack_prefix}_p != #{stack_prefix}) \\
{ \\
#{stack_prefix}_p -= 1; \\
} \\
else \\
{ \\
YYDPRINTF ((stderr, "Try to pop empty #{state_name} stack\\n")); \\
} \\
} \\
while (0)
# define YYSET_STATE_#{state_name.upcase}(value) \\
do \\
{ \\
YYDPRINTF ((stderr, "Set #{state_name}\\n")); \\
*#{stack_prefix}_p = value; \\
} \\
while (0)
# define YY_STATE_#{state_name.upcase} #{stack_prefix}_p
FUNC
end

def states_stacks
<<~STACKS
/* The parser state stack (#{stack_prefix}): array, bottom, top. */
int #{stack_prefix}_a[YYINITDEPTH];
int *#{stack_prefix} = #{stack_prefix}_a;
int *#{stack_prefix}_p = #{stack_prefix};
STACKS
end

def state_name
state_id.s_value
end

def enum_name
"yyparser_state_#{state_name}"
end

def enum_type
"#{enum_name}_t"
end

def enum_body
state_list.map do |state|
state.s_value
end.join(",\n ")
end

def int_to_name
state_list.map do |state|
"\"#{state.s_value}\""
end << "YY_NULLPTR"
end

def enum_name_table_name
"#{enum_name}_names"
end

def stack_prefix
"yyparser_state_#{state_name}"
end
end
end
Expand Down
65 changes: 6 additions & 59 deletions lib/lrama/output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -359,73 +359,20 @@ def percent_code(name)
end

def parser_states_enums
@grammar.parser_states.map do |parser_state|
enum_name = "yyparser_state_#{parser_state.state_id.s_value}"

enum_body = parser_state.state_list.map do |state|
state.s_value
end.join(",\n ")

int_to_name = parser_state.state_list.map do |state|
"\"#{state.s_value}\""
end << "YY_NULLPTR"

<<~ENUM
enum #{enum_name}
{
#{enum_body}
};
typedef enum #{enum_name} #{enum_name}_t;
static const char *const #{enum_name}name[] = {
#{int_to_name.join(", ")}
};
YY_ATTRIBUTE_UNUSED
static const char *
#{enum_name}_name (#{enum_name}_t num)
{
return #{enum_name}name[num];
}
# define YY_STATE_#{parser_state.state_id.s_value.upcase}_NAME #{enum_name}_name (*yyparser_state_#{parser_state.state_id.s_value}_p)
ENUM
@grammar.parser_states.map do |ps|
ps.enum_definition
end
end

def parser_states_stacks
@grammar.parser_states.map do |parser_state|
"yyparser_state_#{parser_state.state_id.s_value}"
@grammar.parser_states.map do |ps|
ps.states_stacks
end
end

def parser_states_functions
# TODO: Stack check for push and pop
@grammar.parser_states.map do |parser_state|
<<~FUNC
# define YYPUSH_STATE_#{parser_state.state_id.s_value.upcase}(value) \\
do \\
{ \\
*++yyparser_state_#{parser_state.state_id.s_value}_p = value; \\
} \\
while (0)
# define YYPOP_STATE_#{parser_state.state_id.s_value.upcase}() \\
do \\
{ \\
yyparser_state_#{parser_state.state_id.s_value}_p -= 1; \\
} \\
while (0)
# define YYSET_STATE_#{parser_state.state_id.s_value.upcase}(value) \\
do \\
{ \\
*yyparser_state_#{parser_state.state_id.s_value}_p = value; \\
} \\
while (0)
# define YY_STATE_#{parser_state.state_id.s_value.upcase} yyparser_state_#{parser_state.state_id.s_value}_p
FUNC
@grammar.parser_states.map do |ps|
ps.states_functions
end
end

Expand Down
11 changes: 11 additions & 0 deletions sig/lrama/grammar/parser_state.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ module Lrama
attr_reader state_list: Array[Lexer::Token::Ident]

def initialize: (state_id: Lexer::Token::Ident, state_list: Array[Lexer::Token::Ident]) -> void

def enum_definition: () -> String
def states_functions: () -> String
def states_stacks: () -> String
def state_name: () -> String
def enum_name: () -> String
def enum_type: () -> String
def enum_body: () -> String
def int_to_name: () -> Array[String]
def enum_name_table_name: () -> String
def stack_prefix: () -> String
end
end
end
144 changes: 144 additions & 0 deletions spec/lrama/grammar/parser_state_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
RSpec.describe Lrama::Grammar::ParserState do
let(:location) { Lrama::Lexer::Location.new(first_line: 1, first_column: 0, last_line: 1, last_column: 0) }
let(:state_id) { Lrama::Lexer::Token::Ident.new(s_value: "in_rescue", location: location) }
let(:state_list) do
[
Lrama::Lexer::Token::Ident.new(s_value: "before_rescue", location: location),
Lrama::Lexer::Token::Ident.new(s_value: "after_rescue", location: location),
Lrama::Lexer::Token::Ident.new(s_value: "after_else", location: location),
Lrama::Lexer::Token::Ident.new(s_value: "after_ensure", location: location)
]
end
let(:parser_state) { Lrama::Grammar::ParserState.new(state_id: state_id, state_list: state_list) }

describe "#enum_definition" do
it "returns enum definition" do
expect(parser_state.enum_definition).to eq <<~ENUM
enum yyparser_state_in_rescue
{
before_rescue,
after_rescue,
after_else,
after_ensure
};
typedef enum yyparser_state_in_rescue yyparser_state_in_rescue_t;
static const char *const yyparser_state_in_rescue_names[] = {
"before_rescue", "after_rescue", "after_else", "after_ensure", YY_NULLPTR
};
YY_ATTRIBUTE_UNUSED
static const char *
yyparser_state_in_rescue_name (yyparser_state_in_rescue_t num)
{
return yyparser_state_in_rescue_names[num];
}
# define YY_STATE_IN_RESCUE_NAME yyparser_state_in_rescue_name (*yyparser_state_in_rescue_p)
ENUM
end
end

describe "#states_functions" do
it "returns states functions" do
expect(parser_state.states_functions).to eq <<~FUNC
# define YYPUSH_STATE_IN_RESCUE(value) \\
do \\
{ \\
YYDPRINTF ((stderr, "Push in_rescue\\n")); \\
*++yyparser_state_in_rescue_p = value; \\
} \\
while (0)
# define YYPOP_STATE_IN_RESCUE() \\
do \\
{ \\
YYDPRINTF ((stderr, "Pop in_rescue\\n")); \\
if (yyparser_state_in_rescue_p != yyparser_state_in_rescue) \\
{ \\
yyparser_state_in_rescue_p -= 1; \\
} \\
else \\
{ \\
YYDPRINTF ((stderr, "Try to pop empty in_rescue stack\\n")); \\
} \\
} \\
while (0)
# define YYSET_STATE_IN_RESCUE(value) \\
do \\
{ \\
YYDPRINTF ((stderr, "Set in_rescue\\n")); \\
*yyparser_state_in_rescue_p = value; \\
} \\
while (0)
# define YY_STATE_IN_RESCUE yyparser_state_in_rescue_p
FUNC
end
end

describe "#states_stacks" do
it "returns states stacks" do
expect(parser_state.states_stacks).to eq <<~STACKS
/* The parser state stack (yyparser_state_in_rescue): array, bottom, top. */
int yyparser_state_in_rescue_a[YYINITDEPTH];
int *yyparser_state_in_rescue = yyparser_state_in_rescue_a;
int *yyparser_state_in_rescue_p = yyparser_state_in_rescue;
STACKS
end
end

describe "#state_name" do
it "returns state name" do
expect(parser_state.state_name).to eq "in_rescue"
end
end

describe "#enum_name" do
it "returns enum name" do
expect(parser_state.enum_name).to eq "yyparser_state_in_rescue"
end
end

describe "#enum_type" do
it "returns enum type" do
expect(parser_state.enum_type).to eq "yyparser_state_in_rescue_t"
end
end

describe "#enum_body" do
it "returns enum body" do
expect(parser_state.enum_body).to eq <<~BODY.chomp
before_rescue,
after_rescue,
after_else,
after_ensure
BODY
end
end

describe "#int_to_name" do
it "returns int to name table" do
expect(parser_state.int_to_name).to eq [
"\"before_rescue\"",
"\"after_rescue\"",
"\"after_else\"",
"\"after_ensure\"",
"YY_NULLPTR"
]
end
end

describe "#enum_name_table_name" do
it "returns table name" do
expect(parser_state.enum_name_table_name).to eq "yyparser_state_in_rescue_names"
end
end

describe "#stack_prefix" do
it "returns prefix" do
expect(parser_state.stack_prefix).to eq "yyparser_state_in_rescue"
end
end
end
7 changes: 2 additions & 5 deletions template/bison/yacc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1519,11 +1519,8 @@ YYLTYPE yylloc = yyloc_default;
YYLTYPE *yyls = yylsa;
YYLTYPE *yylsp = yyls;

<%- output.parser_states_stacks.each do |parser_state| -%>
/* The parser state stack (<%= parser_state %>): array, bottom, top. */
int <%= parser_state %>_a[YYINITDEPTH];
int *<%= parser_state %> = <%= parser_state %>_a;
int *<%= parser_state %>_p = <%= parser_state %>;
<%- output.parser_states_stacks.each do |states_stacks| -%>
<%= states_stacks %>
<%- end -%>

int yyn;
Expand Down

0 comments on commit 8412c68

Please sign in to comment.