42sh/src/parser/grammar.c

171 lines
3.9 KiB
C
Raw Normal View History

// === Includes
#include "grammar.h"
#include <stdio.h>
#include <stdlib.h>
#include "grammar_basic.h"
// === Static variables
// rule-indexed array containing firsts
static struct firsts_list *firsts_map = NULL;
// === Static functions
/* @brief Add a token to a rule's firsts (in firsts_map)
*
* @arg rule the rule to which add a first
* @arg token the token to add to the rule's firsts
* @return true on success, false on error
*/
static bool add_first(enum rule rule, enum token_type token)
{
struct firsts_list *item = &firsts_map[rule];
if (item->tokens != NULL)
{
// Check for duplicates
for (size_t i = 0; i < item->list_length; i++)
{
if (item->tokens[i] == token)
return true;
}
// Append
item->list_length++;
item->tokens = realloc(
item->tokens, (item->list_length) * sizeof(enum token_type));
}
else
{
// Create entry
item->list_length = 1;
item->tokens = calloc(1, sizeof(enum token_type));
}
// Check for alloc error
if (item->tokens == NULL)
{
item->list_length = 0;
return false;
}
// Fill
item->list_length++;
item->tokens[item->list_length - 1] = token;
return true;
}
/* @brief initializes the firsts_map static variable (does not populate it)
* @return true on success, false on error
*/
static bool init_firsts_map(void)
{
firsts_map = calloc(NUMBER_OF_RULES, sizeof(struct firsts_list));
if (firsts_map == NULL)
{
puts("Internal error: couldn't create the firsts_map (is your memory "
"full ?)");
return false;
}
return true;
}
// === Functions
bool grammar_init(void)
{
// Initialize the firsts map
bool success = init_firsts_map();
if (success != true)
return false;
// Populate the firsts map
add_first(RULE_INPUT, TOKEN_WORD);
add_first(RULE_INPUT, TOKEN_IF);
add_first(RULE_INPUT, TOKEN_NEWLINE);
add_first(RULE_INPUT, TOKEN_EOF);
add_first(RULE_LIST, TOKEN_WORD);
add_first(RULE_LIST, TOKEN_IF);
add_first(RULE_AND_OR, TOKEN_WORD);
add_first(RULE_AND_OR, TOKEN_IF);
add_first(RULE_PIPELINE, TOKEN_WORD);
add_first(RULE_PIPELINE, TOKEN_IF);
add_first(RULE_COMMAND, TOKEN_WORD);
add_first(RULE_COMMAND, TOKEN_IF);
add_first(RULE_SIMPLE_COMMAND, TOKEN_WORD);
add_first(RULE_SHELL_COMMAND, TOKEN_IF);
add_first(RULE_IF, TOKEN_IF);
add_first(RULE_COMPOUND_LIST, TOKEN_NEWLINE);
add_first(RULE_COMPOUND_LIST, TOKEN_WORD);
add_first(RULE_COMPOUND_LIST, TOKEN_IF);
add_first(RULE_ELSE_CLAUSE, TOKEN_ELSE);
add_first(RULE_ELSE_CLAUSE, TOKEN_ELIF);
add_first(RULE_ELEMENT, TOKEN_WORD);
add_first(RULE_ELEMENT, TOKEN_IONUMBER);
add_first(RULE_ELEMENT, TOKEN_REDIRECTION);
add_first(RULE_REDIRECTION, TOKEN_IONUMBER);
add_first(RULE_REDIRECTION, TOKEN_REDIRECTION);
add_first(RULE_PREFIX, TOKEN_IONUMBER);
add_first(RULE_PREFIX, TOKEN_REDIRECTION);
return true;
}
void grammar_close(void)
{
// Deep free firsts map
for (int i = 0; i < NUMBER_OF_RULES; i++)
{
if (firsts_map[i].tokens != NULL)
{
free(firsts_map[i].tokens);
}
}
free(firsts_map);
firsts_map = NULL;
}
struct firsts_list *first(enum rule rule)
{
if (firsts_map == NULL || firsts_map[rule].tokens == NULL)
{
puts("Internal error: attempted to get the firsts of a rule without "
"properly initializing the firsts map");
return NULL;
}
return &firsts_map[rule];
}
bool is_first(struct token token, enum rule rule)
{
struct firsts_list *firsts = &firsts_map[rule];
for (size_t i = 0; i < firsts->list_length; i++)
{
if (firsts->tokens[i] == token.type)
return true;
}
return false;
}
struct ast *parse_input(struct lexer_context *ctx)
{
return parse_list(ctx);
}