42sh/src/parser/grammar.c

217 lines
5 KiB
C
Raw Normal View History

// === Includes
#include "grammar.h"
#include <stdio.h>
#include <stdlib.h>
#include "../lexer/lexer.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->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)
{
perror("Internal error: couldn't create the firsts_map (is your memory "
2026-01-27 19:56:33 +01:00
"full ?)");
return false;
}
return true;
}
/* @brief: add all the redirection token_types to the first of [rule].
* this also contains IONUMBER
*/
static void add_first_redir(enum rule rule)
{
add_first(rule, TOKEN_IONUMBER);
add_first(rule, TOKEN_REDIR_LEFT);
add_first(rule, TOKEN_REDIR_RIGHT);
add_first(rule, TOKEN_REDIR_LEFT_RIGHT);
add_first(rule, TOKEN_REDIR_DOUBLE_RIGHT);
add_first(rule, TOKEN_REDIR_LEFT_AMP);
add_first(rule, TOKEN_REDIR_RIGHT_AMP);
add_first(rule, TOKEN_REDIR_RIGHT_PIPE);
}
// === 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_COMMAND, TOKEN_NEGATION);
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_COMMAND, TOKEN_NEGATION);
add_first(RULE_AND_OR, TOKEN_WORD);
add_first(RULE_AND_OR, TOKEN_IF);
add_first(RULE_COMMAND, TOKEN_NEGATION);
add_first(RULE_PIPELINE, TOKEN_WORD);
add_first(RULE_PIPELINE, TOKEN_IF);
add_first(RULE_COMMAND, TOKEN_NEGATION);
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_redir(RULE_ELEMENT);
add_first_redir(RULE_REDIRECTION);
add_first_redir(RULE_PREFIX);
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)
{
perror("Internal error: attempted to get the firsts of a rule without "
2026-01-27 19:56:33 +01:00
"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)
{
2026-01-24 16:48:21 +01:00
struct token *token = PEEK_TOKEN();
if (token->type == TOKEN_EOF)
2026-01-27 18:00:59 +01:00
{
POP_TOKEN();
return ast_create_end();
}
2026-01-24 16:48:21 +01:00
if (token->type == TOKEN_NEWLINE)
{
POP_TOKEN();
return ast_create_list(NULL);
}
struct ast *ast = parse_list(ctx);
if (ast == NULL)
return NULL;
token = PEEK_TOKEN();
if (token->type == TOKEN_NEWLINE || token->type == TOKEN_EOF)
{
if (token->type == TOKEN_NEWLINE)
{
2026-01-24 16:48:21 +01:00
POP_TOKEN();
}
2026-01-24 16:48:21 +01:00
return ast;
}
perror("Syntax error: expected newline or EOF after list");
2026-01-24 16:48:21 +01:00
ast_free(&ast);
return NULL;
}