feat: made the firsts system for parser (not yet populated)

This commit is contained in:
Gu://em_ 2026-01-24 13:06:39 +01:00
parent 32e182bd50
commit da1a73c264
3 changed files with 129 additions and 22 deletions

View file

@ -1,30 +1,105 @@
#define _POSIX_C_SOURCE 200809L
// === Includes // === Includes
#include "grammar.h" #include "grammar.h"
#include "../utils/hash_map/hash_map.h" #include <stdio.h>
#include <stdlib.h>
#include "grammar_basic.h" #include "grammar_basic.h"
// === Static variables // === Static variables
static struct hash_map *firsts_map = NULL; // rule-indexed array containing firsts
static struct firsts_list *firsts_map = NULL;
// === Static functions // === Static functions
static enum token_type first(enum rule r)
/* @brief get the first accepted tokens of a rule
*
* @arg r the rule
* @return the accepted tokens as a firsts_list struct
*/
static struct firsts_list *first(enum rule r)
{ {
// TODO if (firsts_map == NULL || firsts_map[r].tokens == NULL)
return TOKEN_NULL; {
puts("Internal error: attempted to get the firsts of a rule without "
"properly initializing the firsts map");
return NULL;
}
return &firsts_map[r];
}
/* @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, struct token 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].type == token.type)
return true;
}
// Append
item->list_length++;
item->tokens = realloc(
item->tokens, (item->list_length) * sizeof(struct firsts_list));
}
else
{
// Create entry
item->tokens =
calloc(item->list_length + 1, sizeof(struct firsts_list));
}
// 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 // === Functions
bool grammar_init(void) bool grammar_init(void)
{ {
// Create firsts hashmap // Initialize the firsts map
// TODO bool success = init_firsts_map();
if (success != true)
return false;
// Populate the hashmap // Populate the firsts map
// TODO // TODO
return true; return true;
@ -32,7 +107,16 @@ bool grammar_init(void)
void grammar_close(void) void grammar_close(void)
{ {
// TODO free hashmap // 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 ast *parse_input(struct lexer_context *ctx) struct ast *parse_input(struct lexer_context *ctx)

View file

@ -26,17 +26,23 @@
// === Structures // === Structures
enum rule { enum rule {
RULE_NULL, RULE_NULL = 0,
RULE_INPUT, RULE_INPUT,
RULE_LIST, RULE_LIST,
RULE_AND_OR, RULE_AND_OR,
RULE_PIPELINE, RULE_PIPELINE,
RULE_COMMAND, RULE_COMMAND,
RULE_SIMPLE_COMMAND, RULE_SIMPLE_COMMAND,
RULE_SHELL_COMMAND, RULE_SHELL_COMMAND,
RULE_IF, RULE_IF,
RULE_COMPOUND_LIST, RULE_COMPOUND_LIST,
RULE_ELSE_CLAUSE RULE_ELSE_CLAUSE,
NUMBER_OF_RULES
};
struct firsts_list {
struct token* tokens; // Heap allocated array
size_t list_length;
}; };
// === Functions // === Functions

View file

@ -10,18 +10,24 @@
* ends by a newline * ends by a newline
* *
* @code list = and_or { ';' and_or } [ ';' ] ; * @code list = and_or { ';' and_or } [ ';' ] ;
*
* @first first(and_or)
*/ */
struct ast *parse_list(struct lexer_context *ctx); struct ast *parse_list(struct lexer_context *ctx);
/* @brief Only parses a pipeline rule for the moment /* @brief Only parses a pipeline rule for the moment
* *
* @code and_or = pipeline { ( '&&' | '||' ) {'\n'} pipeline } ; * @code and_or = pipeline { ( '&&' | '||' ) {'\n'} pipeline } ;
*
* @first first(pipeline)
*/ */
struct ast *parse_and_or(struct lexer_context *ctx); struct ast *parse_and_or(struct lexer_context *ctx);
/* @brief Only parses a command rule for the moment /* @brief Only parses a command rule for the moment
* *
* @code pipeline = command ; * @code pipeline = command ;
*
* @first first(command)
*/ */
struct ast *parse_pipeline(struct lexer_context *ctx); struct ast *parse_pipeline(struct lexer_context *ctx);
@ -34,6 +40,7 @@ struct ast *parse_pipeline(struct lexer_context *ctx);
* @code command = simple_command * @code command = simple_command
* | shell_command * | shell_command
* ; * ;
* @first first(simple_command), first(shell_command)
*/ */
struct ast *parse_command(struct lexer_context *ctx); struct ast *parse_command(struct lexer_context *ctx);
@ -41,18 +48,24 @@ struct ast *parse_command(struct lexer_context *ctx);
* ending by a separator * ending by a separator
* *
* @code simple_command = WORD { element } ; * @code simple_command = WORD { element } ;
*
* @first WORD
*/ */
struct ast *parse_simple_command(struct lexer_context *ctx); struct ast *parse_simple_command(struct lexer_context *ctx);
/* @brief Only parses if rules for the moment /* @brief Only parses if rules for the moment
* *
* @code shell_command = if_rule ; * @code shell_command = if_rule ;
*
* @first first(if_rule)
*/ */
struct ast *parse_shell_command(struct lexer_context *ctx); struct ast *parse_shell_command(struct lexer_context *ctx);
/* @brief Parses a if rule (condition, then-clause, elif-clause, else-clause) /* @brief Parses a if rule (condition, then-clause, elif-clause, else-clause)
* *
* @code if_rule = 'if' compound_list 'then' compound_list [else_clause] 'fi' ; * @code if_rule = 'if' compound_list 'then' compound_list [else_clause] 'fi' ;
*
* @first TOKEN_IF
*/ */
struct ast *parse_if_rule(struct lexer_context *ctx); struct ast *parse_if_rule(struct lexer_context *ctx);
@ -61,6 +74,8 @@ struct ast *parse_if_rule(struct lexer_context *ctx);
* *
* @code compound_list = {'\n'} and_or { ( ';' | '\n' ) {'\n'} and_or } [';'] * @code compound_list = {'\n'} and_or { ( ';' | '\n' ) {'\n'} and_or } [';']
* {'\n'} ; * {'\n'} ;
*
* @first TOKEN_NEWLINE, first(and_or)
*/ */
struct ast *parse_compound_list(struct lexer_context *ctx); struct ast *parse_compound_list(struct lexer_context *ctx);
@ -69,6 +84,8 @@ struct ast *parse_compound_list(struct lexer_context *ctx);
* @code else_clause = 'else' compound_list * @code else_clause = 'else' compound_list
* | 'elif' compound_list 'then' compound_list [else_clause] * | 'elif' compound_list 'then' compound_list [else_clause]
* ; * ;
*
* @first TOKEN_ELSE, TOKEN_ELIF
*/ */
struct ast *parse_else_clause(struct lexer_context *ctx); struct ast *parse_else_clause(struct lexer_context *ctx);