merge parser into dev with ast loops
This commit is contained in:
commit
4d271981df
10 changed files with 343 additions and 26 deletions
|
|
@ -73,7 +73,9 @@ enum token_type
|
|||
TOKEN_WHILE,
|
||||
TOKEN_UNTIL,
|
||||
TOKEN_CASE,
|
||||
TOKEN_EXPORT
|
||||
TOKEN_EXPORT,
|
||||
TOKEN_DO,
|
||||
TOKEN_DONE
|
||||
};
|
||||
|
||||
struct token
|
||||
|
|
|
|||
|
|
@ -81,3 +81,145 @@ struct ast *parse_prefix(struct lexer_context *ctx)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO NOT IMPLEMENTED
|
||||
struct ast *parse_funcdec(struct lexer_context *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
perror("Error: usage of a not implemented function (parse_funcdec)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ast *parse_for(struct lexer_context *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
perror("Error: usage of a not implemented function (parse_for)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ast *parse_while(struct lexer_context *ctx)
|
||||
{
|
||||
struct token *token = PEEK_TOKEN();
|
||||
|
||||
// 'while'
|
||||
if (token->type != TOKEN_WHILE)
|
||||
{
|
||||
perror(
|
||||
"Internal error: expected a TOKEN_WHILE but got a different type");
|
||||
return NULL;
|
||||
}
|
||||
POP_TOKEN();
|
||||
|
||||
// condition
|
||||
struct ast *condition = parse_compound_list(ctx);
|
||||
if (condition == NULL)
|
||||
return NULL;
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// 'do'
|
||||
if (token->type != TOKEN_DO)
|
||||
{
|
||||
ast_free(&condition);
|
||||
perror("Syntax error: expected the 'do' keyowrd but got a different "
|
||||
"token");
|
||||
return NULL;
|
||||
}
|
||||
POP_TOKEN();
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// body
|
||||
struct ast *body = parse_compound_list(ctx);
|
||||
if (body == NULL)
|
||||
{
|
||||
ast_free(&condition);
|
||||
return NULL;
|
||||
}
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// 'done'
|
||||
if (token->type != TOKEN_DONE)
|
||||
{
|
||||
ast_free(&condition);
|
||||
perror("Syntax error: expected the 'done' keyowrd but got a different "
|
||||
"token");
|
||||
return NULL;
|
||||
}
|
||||
POP_TOKEN();
|
||||
|
||||
struct ast *result = ast_create_loop(condition, body);
|
||||
if (result == NULL)
|
||||
{
|
||||
ast_free(&condition);
|
||||
ast_free(&body);
|
||||
perror("Internal error: could not create ast node (is your memory full "
|
||||
"?)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ast *parse_until(struct lexer_context *ctx)
|
||||
{
|
||||
struct token *token = PEEK_TOKEN();
|
||||
|
||||
// 'while'
|
||||
if (token->type != TOKEN_UNTIL)
|
||||
{
|
||||
perror(
|
||||
"Internal error: expected a TOKEN_WHILE but got a different type");
|
||||
return NULL;
|
||||
}
|
||||
POP_TOKEN();
|
||||
|
||||
// condition
|
||||
struct ast *condition = parse_compound_list(ctx);
|
||||
if (condition == NULL)
|
||||
return NULL;
|
||||
condition =
|
||||
ast_create_neg(true, condition); // TODO check result (beware to not
|
||||
// exceed function lines limit)
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// 'do'
|
||||
if (token->type != TOKEN_DO)
|
||||
{
|
||||
ast_free(&condition);
|
||||
perror("Syntax error: expected the 'do' keyowrd but got a different "
|
||||
"token");
|
||||
return NULL;
|
||||
}
|
||||
POP_TOKEN();
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// body
|
||||
struct ast *body = parse_compound_list(ctx);
|
||||
if (body == NULL)
|
||||
{
|
||||
ast_free(&condition);
|
||||
return NULL;
|
||||
}
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// 'done'
|
||||
if (token->type != TOKEN_DONE)
|
||||
{
|
||||
ast_free(&condition);
|
||||
perror("Syntax error: expected the 'done' keyowrd but got a different "
|
||||
"token");
|
||||
return NULL;
|
||||
}
|
||||
POP_TOKEN();
|
||||
|
||||
struct ast *result = ast_create_loop(condition, body);
|
||||
if (result == NULL)
|
||||
{
|
||||
ast_free(&condition);
|
||||
ast_free(&body);
|
||||
perror("Internal error: could not create ast node (is your memory full "
|
||||
"?)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,4 +24,46 @@ struct ast *parse_redirection(struct lexer_context *ctx);
|
|||
*/
|
||||
struct ast *parse_prefix(struct lexer_context *ctx);
|
||||
|
||||
/*
|
||||
* @brief parses a funcdec rule
|
||||
* @warning NOT IMPLEMENTED
|
||||
*
|
||||
* @code funcdec = WORD '(' ')' {'\n'} shell_command ;
|
||||
*
|
||||
* @first WORD
|
||||
*/
|
||||
struct ast *parse_funcdec(struct lexer_context *ctx);
|
||||
|
||||
/*
|
||||
* @brief parses a for rule
|
||||
* @warning NOT IMPLEMENTED
|
||||
*
|
||||
* @code rule_for = 'for' WORD
|
||||
* ( [';'] | [ {'\n'} 'in' { WORD } ( ';' | '\n' ) ] )
|
||||
* {'\n'} 'do' compound_list 'done' ;
|
||||
*
|
||||
* @first TOKEN_FOR
|
||||
*/
|
||||
struct ast *parse_for(struct lexer_context *ctx);
|
||||
|
||||
/*
|
||||
* @brief parses a while rule
|
||||
* @warning NOT IMPLEMENTED
|
||||
*
|
||||
* @code rule_while = 'while' compound_list 'do' compound_list 'done' ;
|
||||
*
|
||||
* @first TOKEN_WHILE
|
||||
*/
|
||||
struct ast *parse_while(struct lexer_context *ctx);
|
||||
|
||||
/*
|
||||
* @brief parses an until rule
|
||||
* @warning NOT IMPLEMENTED
|
||||
*
|
||||
* @code rule_until = 'until' compound_list 'do' compound_list 'done' ;
|
||||
*
|
||||
* @first TOKEN_UNTIL
|
||||
*/
|
||||
struct ast *parse_until(struct lexer_context *ctx);
|
||||
|
||||
#endif /* ! GRAMMAR_ADVANCED_H */
|
||||
|
|
|
|||
|
|
@ -26,6 +26,29 @@ static enum ast_and_or_type and_or_tok_to_ast(enum token_type tok_type)
|
|||
}
|
||||
}
|
||||
|
||||
/* @brief: frees command_elements and redirections lists (helper func)
|
||||
* @return: NULL
|
||||
*/
|
||||
static void *err_simple_command(struct list *command_elements,
|
||||
struct list *redirections)
|
||||
{
|
||||
list_deep_destroy(command_elements);
|
||||
list_deep_destroy(redirections);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* @brief: frees all the arguments. (helper func)
|
||||
* @return: NULL.
|
||||
*/
|
||||
static void *err_if_rule(struct ast **cond, struct ast **then_clause,
|
||||
struct ast **else_clause)
|
||||
{
|
||||
ast_free(cond);
|
||||
ast_free(then_clause);
|
||||
ast_free(else_clause);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// === Functions
|
||||
|
||||
struct ast *parse_list(struct lexer_context *ctx)
|
||||
|
|
@ -73,16 +96,11 @@ struct ast *parse_and_or(struct lexer_context *ctx)
|
|||
|
||||
while (token->type == TOKEN_AND || token->type == TOKEN_OR)
|
||||
{
|
||||
// Set left part
|
||||
|
||||
// Build AST (left part)
|
||||
enum ast_and_or_type type = and_or_tok_to_ast(token->type);
|
||||
struct ast *left = result;
|
||||
|
||||
// eat and_or token
|
||||
token = POP_TOKEN();
|
||||
|
||||
// Set type
|
||||
enum ast_and_or_type type = and_or_tok_to_ast(token->type);
|
||||
|
||||
POP_TOKEN();
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// Skip newlines
|
||||
|
|
@ -94,6 +112,12 @@ struct ast *parse_and_or(struct lexer_context *ctx)
|
|||
|
||||
// Right part
|
||||
struct ast *right = parse_pipeline(ctx);
|
||||
if (right == NULL)
|
||||
{
|
||||
ast_free(&left);
|
||||
return NULL;
|
||||
}
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
result = ast_create_and_or(left, right, type);
|
||||
if (result == NULL)
|
||||
|
|
@ -120,30 +144,33 @@ struct ast *parse_pipeline(struct lexer_context *ctx)
|
|||
token = PEEK_TOKEN();
|
||||
}
|
||||
|
||||
// command rule
|
||||
struct ast *left = parse_command(ctx);
|
||||
token = PEEK_TOKEN();
|
||||
if (negation)
|
||||
{
|
||||
left = ast_create_neg(negation, left);
|
||||
}
|
||||
|
||||
token = PEEK_TOKEN();
|
||||
// Pipes
|
||||
while (token->type == TOKEN_PIPE)
|
||||
{
|
||||
POP_TOKEN();
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// skip newlines
|
||||
token = PEEK_TOKEN();
|
||||
while (token->type == TOKEN_NEWLINE)
|
||||
{
|
||||
POP_TOKEN();
|
||||
token = PEEK_TOKEN();
|
||||
}
|
||||
|
||||
// command rule
|
||||
struct ast *right = parse_command(ctx);
|
||||
token = PEEK_TOKEN();
|
||||
|
||||
// Create AST
|
||||
left = ast_create_pipe(left, right);
|
||||
token = PEEK_TOKEN();
|
||||
}
|
||||
|
||||
return left;
|
||||
|
|
@ -162,6 +189,11 @@ struct ast *parse_command(struct lexer_context *ctx)
|
|||
{
|
||||
result = parse_shell_command(ctx);
|
||||
}
|
||||
// WARNING funcdec seems to require a LL(2) parser
|
||||
else if (is_first(*token, RULE_FUNCDEC))
|
||||
{
|
||||
result = parse_funcdec(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("Syntax error: unexpected token");
|
||||
|
|
@ -336,19 +368,41 @@ struct ast *parse_element(struct lexer_context *ctx)
|
|||
|
||||
struct ast *parse_shell_command(struct lexer_context *ctx)
|
||||
{
|
||||
return parse_if_rule(ctx);
|
||||
}
|
||||
struct token *token = PEEK_TOKEN();
|
||||
struct ast *result = NULL;
|
||||
|
||||
/* @brief: frees all the arguments. (helper func)
|
||||
* @return: NULL.
|
||||
*/
|
||||
static void *err_if_rule(struct ast **cond, struct ast **then_clause,
|
||||
struct ast **else_clause)
|
||||
{
|
||||
ast_free(cond);
|
||||
ast_free(then_clause);
|
||||
ast_free(else_clause);
|
||||
return NULL;
|
||||
// Grouping
|
||||
// '(' or '{'
|
||||
if (token->type == TOKEN_LEFT_BRACKET || token->type == TOKEN_LEFT_PAREN)
|
||||
{
|
||||
POP_TOKEN();
|
||||
result = parse_compound_list(ctx);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
// ')' or '}'
|
||||
token = PEEK_TOKEN();
|
||||
if (token->type == TOKEN_LEFT_BRACKET
|
||||
|| token->type == TOKEN_LEFT_PAREN)
|
||||
{
|
||||
ast_free(&result);
|
||||
perror("Syntax error: bracket/parenthesis mismatch");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
POP_TOKEN();
|
||||
return result;
|
||||
}
|
||||
else if (is_first(*token, RULE_IF))
|
||||
{
|
||||
return parse_if_rule(ctx);
|
||||
}
|
||||
// TODO loops and case
|
||||
else
|
||||
{
|
||||
perror("Syntax error: unexpected token in parse_shell_command");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct ast *parse_if_rule(struct lexer_context *ctx)
|
||||
|
|
@ -497,7 +551,6 @@ struct ast *parse_else_clause(struct lexer_context *ctx)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// Then clause
|
||||
struct ast *then_content = parse_compound_list(ctx);
|
||||
|
||||
// Eventual else clause (recursive)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ struct ast *parse_pipeline(struct lexer_context *ctx);
|
|||
*
|
||||
* @code command = simple_command
|
||||
* | shell_command
|
||||
*
|
||||
* ;
|
||||
* @first first(simple_command), first(shell_command)
|
||||
*/
|
||||
|
|
@ -72,7 +73,10 @@ struct ast *parse_element(struct lexer_context *ctx);
|
|||
/*
|
||||
* @brief Only parses if rules for the moment
|
||||
*
|
||||
* @code shell_command = if_rule ;
|
||||
* @code shell_command = '{' compound_list '}'
|
||||
* | '(' compound_list ')'
|
||||
* | if_rule
|
||||
* ;
|
||||
*
|
||||
* @first first(if_rule)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ libutils_a_SOURCES = \
|
|||
ast/ast_word.c \
|
||||
ast/ast_neg.c \
|
||||
ast/ast_pipe.c \
|
||||
ast/ast_loop.c \
|
||||
args/args.c \
|
||||
vars/vars.c \
|
||||
ast/ast_assignment.c
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "ast_end.h"
|
||||
#include "ast_if.h"
|
||||
#include "ast_list.h"
|
||||
#include "ast_loop.h"
|
||||
#include "ast_neg.h"
|
||||
#include "ast_pipe.h"
|
||||
#include "ast_redir.h"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ enum ast_type
|
|||
AST_WORD,
|
||||
AST_PIPE,
|
||||
AST_NEG,
|
||||
AST_LOOP,
|
||||
AST_ASSIGNMENT
|
||||
};
|
||||
|
||||
|
|
|
|||
37
src/utils/ast/ast_loop.c
Normal file
37
src/utils/ast/ast_loop.c
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include "ast_loop.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct ast *ast_create_loop(struct ast *condition, struct ast *body)
|
||||
{
|
||||
struct ast_loop *node_data = malloc(sizeof(struct ast_loop));
|
||||
if (!node_data)
|
||||
return NULL;
|
||||
|
||||
node_data->condition = condition;
|
||||
node_data->body = body;
|
||||
|
||||
return ast_create(AST_LOOP, node_data);
|
||||
}
|
||||
|
||||
struct ast_loop *ast_get_loop(struct ast *node)
|
||||
{
|
||||
if (node == NULL || node->type != AST_LOOP)
|
||||
return NULL;
|
||||
return (struct ast_loop *)node->data;
|
||||
}
|
||||
|
||||
bool ast_is_loop(struct ast *node)
|
||||
{
|
||||
return node != NULL && node->type == AST_LOOP;
|
||||
}
|
||||
|
||||
void ast_free_loop(struct ast_loop *loop_data)
|
||||
{
|
||||
if (loop_data == NULL)
|
||||
return;
|
||||
ast_free(&loop_data->condition);
|
||||
ast_free(&loop_data->body);
|
||||
free(loop_data);
|
||||
}
|
||||
34
src/utils/ast/ast_loop.h
Normal file
34
src/utils/ast/ast_loop.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef AST_LOOP_H
|
||||
#define AST_LOOP_H
|
||||
|
||||
#include "ast_base.h"
|
||||
|
||||
struct ast_loop
|
||||
{
|
||||
// Repeat body while condition is true
|
||||
struct ast *condition;
|
||||
struct ast *body;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the given AST node is a loop.
|
||||
*/
|
||||
bool ast_is_loop(struct ast *node);
|
||||
|
||||
/**
|
||||
* Retrieves the loop data from the given AST node.
|
||||
* Assumes that the node is of type AST_LOOP.
|
||||
*/
|
||||
struct ast_loop *ast_get_loop(struct ast *node);
|
||||
|
||||
/**
|
||||
* Creates a new AST node representing a loop.
|
||||
*/
|
||||
struct ast *ast_create_loop(struct ast* condition, struct ast* body);
|
||||
|
||||
/*
|
||||
* @brief: frees the given ast_loop and sets the pointer to NULL.
|
||||
*/
|
||||
void ast_free_loop(struct ast_loop *loop_node);
|
||||
|
||||
#endif /* ! AST_LOOP_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue