This commit is contained in:
Josh Holtrop 2023-08-20 17:25:48 -04:00
parent 7b1d903b00
commit 36213d9e9c
4 changed files with 130 additions and 20 deletions

View File

@ -326,8 +326,8 @@ static lexer_state_id_t check_lexer_transition(uint32_t current_state, uint32_t
static size_t find_longest_match(<%= @grammar.prefix %>context_t * context, static size_t find_longest_match(<%= @grammar.prefix %>context_t * context,
lexer_match_info_t * out_match_info, size_t * out_unexpected_input_length) lexer_match_info_t * out_match_info, size_t * out_unexpected_input_length)
{ {
lexer_match_info_t longest_match; lexer_match_info_t longest_match = {0};
lexer_match_info_t attempt_match; lexer_match_info_t attempt_match = {0};
*out_match_info = longest_match; *out_match_info = longest_match;
uint32_t current_state = lexer_mode_table[context->mode].state_table_offset; uint32_t current_state = lexer_mode_table[context->mode].state_table_offset;
for (;;) for (;;)
@ -427,7 +427,7 @@ static size_t find_longest_match(<%= @grammar.prefix %>context_t * context,
*/ */
static size_t attempt_lex_token(<%= @grammar.prefix %>context_t * context, <%= @grammar.prefix %>token_info_t * out_token_info) static size_t attempt_lex_token(<%= @grammar.prefix %>context_t * context, <%= @grammar.prefix %>token_info_t * out_token_info)
{ {
<%= @grammar.prefix %>token_info_t token_info; <%= @grammar.prefix %>token_info_t token_info = {0};
token_info.position = context->text_position; token_info.position = context->text_position;
token_info.token = INVALID_TOKEN_ID; token_info.token = INVALID_TOKEN_ID;
*out_token_info = token_info; // TODO: remove *out_token_info = token_info; // TODO: remove
@ -437,12 +437,12 @@ static size_t attempt_lex_token(<%= @grammar.prefix %>context_t * context, <%= @
switch (result) switch (result)
{ {
case P_SUCCESS: case P_SUCCESS:
<%= @grammar.prefix %>token_t token_to_accept = match_info.accepting_state.token; <%= @grammar.prefix %>token_t token_to_accept = match_info.accepting_state->token;
if (match_info.accepting_state.code_id != INVALID_USER_CODE_ID) if (match_info.accepting_state->code_id != INVALID_USER_CODE_ID)
{ {
uint8_t const * match = &context->input[context->input_index]; uint8_t const * match = &context->input[context->input_index];
<%= @grammar.prefix %>token_t user_code_token = lexer_user_code(context, <%= @grammar.prefix %>token_t user_code_token = lexer_user_code(context,
match_info.accepting_state.code_id, match, match_info.length, &token_info); match_info.accepting_state->code_id, match, match_info.length, &token_info);
/* An invalid token returned from lexer_user_code() means that the /* An invalid token returned from lexer_user_code() means that the
* user code did not explicitly return a token. So only override * user code did not explicitly return a token. So only override
* the token to return if the user code does explicitly return a * the token to return if the user code does explicitly return a
@ -531,7 +531,7 @@ size_t <%= @grammar.prefix %>lex(<%= @grammar.prefix %>context_t * context, <%=
*************************************************************************/ *************************************************************************/
/** Reduce ID type. */ /** Reduce ID type. */
typedef <%= get_type_for(@parser.reduce_table.size) %> = reduce_id_t; typedef <%= get_type_for(@parser.reduce_table.size) %> reduce_id_t;
/** /**
* A symbol ID can hold either a token ID or a rule set ID. * A symbol ID can hold either a token ID or a rule set ID.
@ -658,7 +658,7 @@ typedef struct
* @param stack * @param stack
* state_values stack structure. * state_values stack structure.
*/ */
void state_values_stack_init(state_values_stack_t * stack) static void state_values_stack_init(state_values_stack_t * stack)
{ {
const size_t initial_capacity = 10u; const size_t initial_capacity = 10u;
stack->length = 0u; stack->length = 0u;
@ -676,7 +676,7 @@ void state_values_stack_init(state_values_stack_t * stack)
* *
* @return Pointer to the state value structure at the given index. * @return Pointer to the state value structure at the given index.
*/ */
state_value_t * state_values_stack_index(state_values_stack_t * stack, int index) static state_value_t * state_values_stack_index(state_values_stack_t * stack, int index)
{ {
if (index >= 0) if (index >= 0)
{ {
@ -694,7 +694,7 @@ state_value_t * state_values_stack_index(state_values_stack_t * stack, int index
* @param stack * @param stack
* state_values stack structure. * state_values stack structure.
*/ */
void state_values_stack_push(state_values_stack_t * stack) static void state_values_stack_push(state_values_stack_t * stack)
{ {
size_t const current_capacity = stack->capacity; size_t const current_capacity = stack->capacity;
size_t const current_length = stack->length; size_t const current_length = stack->length;
@ -702,7 +702,7 @@ void state_values_stack_push(state_values_stack_t * stack)
{ {
size_t const new_capacity = current_capacity * 2u; size_t const new_capacity = current_capacity * 2u;
state_value_t * new_entries = malloc(new_capacity * sizeof(state_value_t)); state_value_t * new_entries = malloc(new_capacity * sizeof(state_value_t));
memcpy(new_entries, stack->entries, current_length * sizeof(state_value_t); memcpy(new_entries, stack->entries, current_length * sizeof(state_value_t));
free(stack->entries); free(stack->entries);
stack->capacity = new_capacity; stack->capacity = new_capacity;
stack->entries = new_entries; stack->entries = new_entries;
@ -719,7 +719,7 @@ void state_values_stack_push(state_values_stack_t * stack)
* @param n * @param n
* Number of states to pop. * Number of states to pop.
*/ */
void state_values_stack_pop(state_values_stack_t * stack, size_t n) static void state_values_stack_pop(state_values_stack_t * stack, size_t n)
{ {
stack->length -= n; stack->length -= n;
} }
@ -730,7 +730,7 @@ void state_values_stack_pop(state_values_stack_t * stack, size_t n)
* @param stack * @param stack
* state_values stack structure. * state_values stack structure.
*/ */
void state_values_stack_free(state_values_stack_t * stack) static void state_values_stack_free(state_values_stack_t * stack)
{ {
free(stack->entries); free(stack->entries);
} }
@ -744,7 +744,7 @@ void state_values_stack_free(state_values_stack_t * stack)
*/ */
static <%= @grammar.prefix %>value_t parser_user_code(uint32_t rule, state_values_stack_t * statevalues, uint32_t n_states) static <%= @grammar.prefix %>value_t parser_user_code(uint32_t rule, state_values_stack_t * statevalues, uint32_t n_states)
{ {
<%= @grammar.prefix %>value_t _pvalue; <%= @grammar.prefix %>value_t _pvalue = {0};
switch (rule) switch (rule)
{ {
@ -821,7 +821,7 @@ static size_t check_reduce(size_t state_id, <%= @grammar.prefix %>token_t token)
* can be accessed with <%= @grammar.prefix %>result(). * can be accessed with <%= @grammar.prefix %>result().
* @retval P_UNEXPECTED_TOKEN * @retval P_UNEXPECTED_TOKEN
* An unexpected token was encountered that does not match any grammar rule. * An unexpected token was encountered that does not match any grammar rule.
* The value context.token holds the unexpected token. * The value context->token holds the unexpected token.
* @reval P_DECODE_ERROR * @reval P_DECODE_ERROR
* The decoder encountered invalid text encoding. * The decoder encountered invalid text encoding.
* @reval P_UNEXPECTED_INPUT * @reval P_UNEXPECTED_INPUT
@ -880,7 +880,7 @@ size_t <%= @grammar.prefix %>parse(<%= @grammar.prefix %>context_t * context)
{ {
/* We shifted a RuleSet. */ /* We shifted a RuleSet. */
state_values_stack_index(&statevalues, -1)->pvalue = reduced_parser_value; state_values_stack_index(&statevalues, -1)->pvalue = reduced_parser_value;
<%= @grammar.prefix %>value_t new_parse_result; <%= @grammar.prefix %>value_t new_parse_result = {0};
reduced_parser_value = new_parse_result; reduced_parser_value = new_parse_result;
reduced_rule_set = INVALID_ID; reduced_rule_set = INVALID_ID;
} }
@ -908,6 +908,7 @@ size_t <%= @grammar.prefix %>parse(<%= @grammar.prefix %>context_t * context)
break; break;
} }
state_values_stack_free(&statevalues); state_values_stack_free(&statevalues);
return result;
} }
/** /**
@ -920,7 +921,7 @@ size_t <%= @grammar.prefix %>parse(<%= @grammar.prefix %>context_t * context)
*/ */
<%= start_rule_type[1] %> <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context) <%= start_rule_type[1] %> <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context)
{ {
return context.parse_result.v_<%= start_rule_type[0] %>; return context->parse_result.v_<%= start_rule_type[0] %>;
} }
/** /**
@ -933,5 +934,5 @@ size_t <%= @grammar.prefix %>parse(<%= @grammar.prefix %>context_t * context)
*/ */
<%= @grammar.prefix %>position_t <%= @grammar.prefix %>position(<%= @grammar.prefix %>context_t * context) <%= @grammar.prefix %>position_t <%= @grammar.prefix %>position(<%= @grammar.prefix %>context_t * context)
{ {
return context.text_position; return context->text_position;
} }

View File

@ -8,6 +8,7 @@
#define PROPANE_PARSER_H #define PROPANE_PARSER_H
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
/************************************************************************** /**************************************************************************
* Public types * Public types
@ -87,6 +88,9 @@ typedef struct
/** Input text. */ /** Input text. */
uint8_t const * input; uint8_t const * input;
/** Input text length. */
size_t input_length;
/** Input text index (byte offset). */ /** Input text index (byte offset). */
size_t input_index; size_t input_index;
@ -105,4 +109,17 @@ typedef struct
<%= @grammar.prefix %>token_t token; <%= @grammar.prefix %>token_t token;
} <%= @grammar.prefix %>context_t; } <%= @grammar.prefix %>context_t;
void <%= @grammar.prefix %>context_init(<%= @grammar.prefix %>context_t * context, uint8_t const * input, size_t input_length);
size_t <%= @grammar.prefix %>decode_code_point(uint8_t const * input, size_t input_length,
<%= @grammar.prefix %>code_point_t * out_code_point, uint8_t * out_code_point_length);
size_t <%= @grammar.prefix %>lex(<%= @grammar.prefix %>context_t * context, <%= @grammar.prefix %>token_info_t * out_token_info);
size_t <%= @grammar.prefix %>parse(<%= @grammar.prefix %>context_t * context);
<%= start_rule_type[1] %> <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context);
<%= @grammar.prefix %>position_t <%= @grammar.prefix %>position(<%= @grammar.prefix %>context_t * context);
#endif #endif

View File

@ -28,10 +28,10 @@ describe Propane do
"spec/run/testparser#{name}.#{options[:language]}" "spec/run/testparser#{name}.#{options[:language]}"
end end
case options[:language] case options[:language]
when "c"
result = system(*%w[gcc -Wall -o spec/run/testparser -Ispec -Ispec/run], *parsers, *test_files)
when "d" when "d"
result = system(*%w[ldc2 --unittest -of spec/run/testparser -Ispec], *parsers, *test_files, "spec/testutils.d") result = system(*%w[ldc2 --unittest -of spec/run/testparser -Ispec], *parsers, *test_files, "spec/testutils.d")
when "c"
result = system(*%w[gcc -o spec/run/testparser -Ispec], *parsers, *test_files)
end end
expect(result).to be_truthy expect(result).to be_truthy
end end

92
spec/test_lexer.c Normal file
View File

@ -0,0 +1,92 @@
#include "testparser.h"
#include <assert.h>
#include <string.h>
int main()
{
size_t result;
p_code_point_t code_point;
uint8_t code_point_length;
result = p_decode_code_point((uint8_t const *)"5", 1u, &code_point, &code_point_length);
assert(result == P_SUCCESS);
assert(code_point == '5');
assert(code_point_length == 1u);
result = p_decode_code_point((uint8_t const *)"", 0u, &code_point, &code_point_length);
assert(result == P_EOF);
result = p_decode_code_point((uint8_t const *)"\xC2\xA9", 2u, &code_point, &code_point_length);
assert(result == P_SUCCESS);
assert(code_point == 0xA9u);
assert(code_point_length == 2u);
result = p_decode_code_point((uint8_t const *)"\xf0\x9f\xa7\xa1", 4u, &code_point, &code_point_length);
assert(result == P_SUCCESS);
assert(code_point == 0x1F9E1u);
assert(code_point_length == 4u);
result = p_decode_code_point((uint8_t const *)"\xf0\x9f\x27", 3u, &code_point, &code_point_length);
assert(result == P_DECODE_ERROR);
result = p_decode_code_point((uint8_t const *)"\xf0\x9f\xa7\xFF", 4u, &code_point, &code_point_length);
assert(result == P_DECODE_ERROR);
result = p_decode_code_point((uint8_t const *)"\xfe", 1u, &code_point, &code_point_length);
assert(result == P_DECODE_ERROR);
p_token_info_t token_info;
char const * input = "5 + 4 * \n677 + 567";
p_context_t context;
p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 0u);
assert(token_info.position.col == 0u);
assert(token_info.length == 1u);
assert(token_info.token == TOKEN_int);
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 0u);
assert(token_info.position.col == 2u);
assert(token_info.length == 1u);
assert(token_info.token == TOKEN_plus);
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 0u);
assert(token_info.position.col == 4u);
assert(token_info.length == 1u);
assert(token_info.token == TOKEN_int);
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 0u);
assert(token_info.position.col == 6u);
assert(token_info.length == 1u);
assert(token_info.token == TOKEN_times);
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u);
assert(token_info.position.col == 0u);
assert(token_info.length == 3u);
assert(token_info.token == TOKEN_int);
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u);
assert(token_info.position.col == 4u);
assert(token_info.length == 1u);
assert(token_info.token == TOKEN_plus);
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u);
assert(token_info.position.col == 6u);
assert(token_info.length == 3u);
assert(token_info.token == TOKEN_int);
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u);
assert(token_info.position.col == 9u);
assert(token_info.length == 0u);
assert(token_info.token == TOKEN___EOF);
p_context_init(&context, (uint8_t const *)"", 0u);
assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 0u);
assert(token_info.position.col == 0u);
assert(token_info.length == 0u);
assert(token_info.token == TOKEN___EOF);
return 0;
}