2026-01-27 19:56:33 +01:00
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
|
|
2026-01-24 15:34:10 +01:00
|
|
|
#include "grammar_advanced.h"
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2026-01-24 16:13:16 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2026-01-24 15:34:10 +01:00
|
|
|
|
2026-01-29 18:21:44 +01:00
|
|
|
#include "grammar.h"
|
2026-01-29 18:46:11 +01:00
|
|
|
#include "grammar_basic.h"
|
2026-01-24 15:34:10 +01:00
|
|
|
|
2026-01-30 20:00:44 +01:00
|
|
|
// === Static functions
|
|
|
|
|
|
2026-01-27 16:17:40 +01:00
|
|
|
static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type)
|
|
|
|
|
{
|
2026-01-27 19:56:33 +01:00
|
|
|
switch (tok_type)
|
2026-01-27 16:17:40 +01:00
|
|
|
{
|
2026-01-27 19:56:33 +01:00
|
|
|
case TOKEN_REDIR_LEFT:
|
|
|
|
|
return AST_REDIR_TYPE_LESS;
|
|
|
|
|
case TOKEN_REDIR_RIGHT:
|
|
|
|
|
return AST_REDIR_TYPE_GREAT;
|
2026-01-28 11:34:29 +01:00
|
|
|
case TOKEN_REDIR_DOUBLE_RIGHT:
|
|
|
|
|
return AST_REDIR_TYPE_DGREAT;
|
|
|
|
|
case TOKEN_REDIR_LEFT_RIGHT:
|
|
|
|
|
return AST_REDIR_TYPE_LESSGREAT;
|
|
|
|
|
case TOKEN_REDIR_LEFT_AMP:
|
|
|
|
|
return AST_REDIR_TYPE_LESSAND;
|
|
|
|
|
case TOKEN_REDIR_RIGHT_AMP:
|
|
|
|
|
return AST_REDIR_TYPE_GREATAND;
|
|
|
|
|
case TOKEN_REDIR_RIGHT_PIPE:
|
|
|
|
|
return AST_REDIR_TYPE_CLOBBER;
|
2026-01-27 19:56:33 +01:00
|
|
|
default:
|
|
|
|
|
return AST_REDIR_TYPE_NULL;
|
2026-01-27 16:17:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-27 16:05:11 +01:00
|
|
|
|
2026-01-30 20:00:44 +01:00
|
|
|
/*
|
|
|
|
|
* @brief parses a while/until loop starting with the condition
|
|
|
|
|
* (after the while/until keyword)
|
|
|
|
|
* @arg negate_condition Set to true for until loops, false for while loops
|
|
|
|
|
*/
|
|
|
|
|
static struct ast *parse_loop(struct lexer_context *ctx, bool negate_condition)
|
|
|
|
|
{
|
|
|
|
|
// condition
|
|
|
|
|
struct ast *condition = parse_compound_list(ctx);
|
|
|
|
|
if (condition == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (negate_condition)
|
|
|
|
|
{
|
|
|
|
|
condition =
|
|
|
|
|
ast_create_neg(true, condition); // TODO check result (beware to not
|
|
|
|
|
// exceed the function lines limit)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct token *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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// === Functions
|
|
|
|
|
|
2026-01-24 15:34:10 +01:00
|
|
|
struct ast *parse_redirection(struct lexer_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct token *token = PEEK_TOKEN();
|
2026-01-24 16:13:16 +01:00
|
|
|
int io_number = -1;
|
|
|
|
|
if (token->type == TOKEN_IONUMBER)
|
|
|
|
|
{
|
|
|
|
|
io_number = atoi(token->data);
|
2026-01-24 15:34:10 +01:00
|
|
|
POP_TOKEN();
|
|
|
|
|
token = PEEK_TOKEN();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-27 16:05:11 +01:00
|
|
|
if (!is_token_redir(token))
|
2026-01-24 15:34:10 +01:00
|
|
|
{
|
2026-01-27 16:05:11 +01:00
|
|
|
perror("Syntax error: expected a redirection token but got something "
|
2026-01-27 19:56:33 +01:00
|
|
|
"else");
|
2026-01-24 15:34:10 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2026-01-27 16:17:40 +01:00
|
|
|
|
|
|
|
|
enum ast_redir_type redir_type = redir_tok_to_ast_type(token->type);
|
2026-01-24 16:13:16 +01:00
|
|
|
POP_TOKEN();
|
|
|
|
|
|
|
|
|
|
token = PEEK_TOKEN();
|
|
|
|
|
if (token->type != TOKEN_WORD)
|
|
|
|
|
{
|
2026-01-27 16:05:11 +01:00
|
|
|
perror("Syntax error: expected a word after redirection");
|
2026-01-24 16:13:16 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
char *target = strdup(token->data);
|
|
|
|
|
POP_TOKEN();
|
|
|
|
|
|
2026-01-27 19:56:33 +01:00
|
|
|
return ast_create_redir(target, io_number, redir_type);
|
2026-01-24 15:34:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ast *parse_prefix(struct lexer_context *ctx)
|
|
|
|
|
{
|
2026-01-29 18:21:44 +01:00
|
|
|
struct token *token = PEEK_TOKEN();
|
2026-01-29 11:18:56 +01:00
|
|
|
if (token->type == TOKEN_ASSIGNMENT_WORD)
|
|
|
|
|
{
|
2026-01-29 18:21:44 +01:00
|
|
|
token = POP_TOKEN();
|
2026-01-30 19:37:05 +01:00
|
|
|
return ast_create_assignment(token->data, false);
|
2026-01-29 11:18:56 +01:00
|
|
|
}
|
|
|
|
|
else if (is_first(*token, RULE_REDIRECTION))
|
|
|
|
|
return parse_redirection(ctx);
|
2026-01-29 12:38:03 +01:00
|
|
|
else
|
2026-01-29 11:18:56 +01:00
|
|
|
{
|
|
|
|
|
perror("Syntax error: expected a prefix (redirection or assignment)");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2026-01-24 15:34:10 +01:00
|
|
|
}
|
2026-01-30 19:48:31 +01:00
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
|
2026-01-30 20:00:44 +01:00
|
|
|
return parse_loop(ctx, true);
|
2026-01-30 19:48:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
2026-01-30 20:00:44 +01:00
|
|
|
return parse_loop(ctx, true);
|
2026-01-30 19:48:31 +01:00
|
|
|
}
|