feat: Merge branch 'lexer' into dev
This commit is contained in:
commit
03c35d5366
6 changed files with 280 additions and 0 deletions
|
|
@ -0,0 +1,67 @@
|
|||
#include "lexer.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "io_backend/io_backend.h"
|
||||
|
||||
static char *end_last_token;
|
||||
static ssize_t remaining_chars;
|
||||
|
||||
char *new_token(char *begin, size_t size)
|
||||
{
|
||||
char *res = calloc(size + 1, sizeof(char));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
strncpy(res, begin, size);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *stream_init(void)
|
||||
{
|
||||
char *stream;
|
||||
|
||||
if (remaining_chars == 0)
|
||||
{
|
||||
remaining_chars = stream_read(&stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream = end_last_token;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
char *get_token(void)
|
||||
{
|
||||
char *stream = stream_init();
|
||||
|
||||
bool inquotes = false;
|
||||
ssize_t i = 0;
|
||||
|
||||
while (i < remaining_chars)
|
||||
{
|
||||
switch (stream[i])
|
||||
{
|
||||
case '\'':
|
||||
inquotes = !inquotes;
|
||||
break;
|
||||
|
||||
case ' ' | '\n' | '\t':
|
||||
if (inquotes)
|
||||
break;
|
||||
else
|
||||
{
|
||||
// token creation
|
||||
// skip blank char
|
||||
// exit from loop
|
||||
char *token = new_token(stream, i);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
remaining_chars -= i;
|
||||
}
|
||||
|
|
@ -1,4 +1,38 @@
|
|||
#ifndef LEXER_H
|
||||
#define LEXER_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/* @return: char*, the next token
|
||||
*
|
||||
*/
|
||||
char *get_token(void);
|
||||
|
||||
/*
|
||||
* @warning: NOT IMPLEMENTED.
|
||||
*
|
||||
* @note: maybe usefull for subshells.
|
||||
*/
|
||||
|
||||
char *get_token_str(void);
|
||||
|
||||
/*
|
||||
* @brief: return a newly allocated token.
|
||||
* This token contains [size] chars, starting from [begin].
|
||||
*
|
||||
* @return: NULL on error, null-terminated char* otherwise.
|
||||
*
|
||||
*/
|
||||
char *new_token(char *begin, ssize_t size);
|
||||
|
||||
/*
|
||||
* @brief: checks if the stream used for the last token creation is empty.
|
||||
* If it is, it calls stream_read() from IO_backend,
|
||||
* and sets [remaing_chars].
|
||||
* If not, it starts from the end of the last token.
|
||||
*
|
||||
* @return: char* stream from which we tokenise.
|
||||
*/
|
||||
char *stream_init(void);
|
||||
|
||||
#endif /* ! LEXER_H */
|
||||
|
|
|
|||
16
src/utils/string_utils/string_utils.c
Normal file
16
src/utils/string_utils/string_utils.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include "utils/string_utils/string_utils.h"
|
||||
|
||||
ssize_t skip_blanks(char **str)
|
||||
{
|
||||
if (str == NULL || *str == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ssize_t skipped = 0;
|
||||
while (str[skipped] != '\0' && !isblank(str[skipped]))
|
||||
{
|
||||
skipped++;
|
||||
}
|
||||
*str += skipped;
|
||||
return skipped;
|
||||
}
|
||||
10
src/utils/string_utils/string_utils.h
Normal file
10
src/utils/string_utils/string_utils.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef STRING_UTILS_H
|
||||
#define STRING_UTILS_H
|
||||
|
||||
/*
|
||||
* @brief: skips blank characters at the beginning of [str].
|
||||
* @return: number of characters skipped.
|
||||
*/
|
||||
ssize_t skip_blanks(char **str);
|
||||
|
||||
#endif /* STRING_UTILS_H */
|
||||
56
tests/unit/lexer/lexer_tests.c
Normal file
56
tests/unit/lexer/lexer_tests.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include <criterion/criterion.h>
|
||||
#include <criterion/new/assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lexer/lexer.h"
|
||||
|
||||
TestSuite(token_creation);
|
||||
|
||||
Test(token_creation, basic)
|
||||
{
|
||||
char input[] = "Hello World";
|
||||
|
||||
char actual[] = new_token(input, 5);
|
||||
char expected[] = "Hello";
|
||||
cr_expect(eq(str, actual, expected));
|
||||
free(actual);
|
||||
}
|
||||
|
||||
Test(token_creation, nul)
|
||||
{
|
||||
char input[] = NULL;
|
||||
|
||||
char actual[] = new_token(input, 5);
|
||||
cr_expect(actual == NULL);
|
||||
}
|
||||
|
||||
Test(token_creation, too_large)
|
||||
{
|
||||
char input[] = "Hel";
|
||||
|
||||
char actual[] = new_token(input, 5);
|
||||
cr_expect(actual == NULL);
|
||||
}
|
||||
|
||||
Test(token_creation, empty)
|
||||
{
|
||||
char input[] = "";
|
||||
|
||||
char actual[] = new_token(input, 5);
|
||||
cr_expect(actual == NULL);
|
||||
}
|
||||
|
||||
Test(token_creation, basic_long)
|
||||
{
|
||||
char input[] = "Hello World! This project is a mini shell, I love BIG G.";
|
||||
|
||||
char actual[] = new_token(input, 42);
|
||||
char expected[] = calloc(42 + 1, sizeof(char));
|
||||
strncpy(input, expected, 42);
|
||||
cr_expect(eq(str, actual, expected));
|
||||
free(actual);
|
||||
free(expected);
|
||||
}
|
||||
97
tests/unit/utils/utils_tests.c
Normal file
97
tests/unit/utils/utils_tests.c
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#include <criterion/criterion.h>
|
||||
#include <criterion/new/assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "utils/string_utils/string_utils.h"
|
||||
|
||||
TestSuite(string_utils);
|
||||
|
||||
Test(string_utils, skipblank_basic)
|
||||
{
|
||||
char input[] = " Hello World";
|
||||
char expected_str[] = "Hello World";
|
||||
|
||||
ssize_t actual = skip_blanks(input);
|
||||
ssize_t expected = 2;
|
||||
cr_expect(eq(str, input, expected_str));
|
||||
cr_expect(actual == expected);
|
||||
}
|
||||
|
||||
Test(string_utils, skipblank_noblank)
|
||||
{
|
||||
char input[] = "Hello World";
|
||||
char expected_str[] = "Hello World";
|
||||
|
||||
ssize_t actual = skip_blanks(input);
|
||||
ssize_t expected = 0;
|
||||
cr_expect(eq(str, input, expected_str));
|
||||
cr_expect(actual == expected);
|
||||
}
|
||||
|
||||
Test(string_utils, skipblank_tab)
|
||||
{
|
||||
char input[] = "\tHello World";
|
||||
char expected_str[] = "Hello World";
|
||||
|
||||
ssize_t actual = skip_blanks(input);
|
||||
ssize_t expected = 1;
|
||||
cr_expect(eq(str, input, expected_str));
|
||||
cr_expect(actual == expected);
|
||||
}
|
||||
|
||||
Test(string_utils, skipblank_space_tab)
|
||||
{
|
||||
char input[] = " \tHello World";
|
||||
char expected_str[] = "Hello World";
|
||||
|
||||
ssize_t actual = skip_blanks(input);
|
||||
ssize_t expected = 2;
|
||||
cr_expect(eq(str, input, expected_str));
|
||||
cr_expect(actual == expected);
|
||||
}
|
||||
|
||||
Test(string_utils, skipblank_2tab_1space)
|
||||
{
|
||||
char input[] = "\t \tHello World";
|
||||
char expected_str[] = "Hello World";
|
||||
|
||||
ssize_t actual = skip_blanks(input);
|
||||
ssize_t expected = 3;
|
||||
cr_expect(eq(str, input, expected_str));
|
||||
cr_expect(actual == expected);
|
||||
}
|
||||
|
||||
Test(string_utils, skipblank_a_lot)
|
||||
{
|
||||
char input[] = "\t \t \tHello World";
|
||||
char expected_str[] = "Hello World";
|
||||
|
||||
ssize_t actual = skip_blanks(input);
|
||||
ssize_t expected = 8;
|
||||
cr_expect(eq(str, input, expected_str));
|
||||
cr_expect(actual == expected);
|
||||
}
|
||||
|
||||
Test(string_utils, skipblank_newline)
|
||||
{
|
||||
char input[] = "\nHello World";
|
||||
char expected_str[] = "\nHello World";
|
||||
|
||||
ssize_t actual = skip_blanks(input);
|
||||
ssize_t expected = 0;
|
||||
cr_expect(eq(str, input, expected_str));
|
||||
cr_expect(actual == expected);
|
||||
}
|
||||
|
||||
Test(string_utils, skipblank_nul)
|
||||
{
|
||||
char *input = NULL;
|
||||
|
||||
ssize_t actual = skip_blanks(input);
|
||||
ssize_t expected = 0;
|
||||
cr_expect(input == NULL);
|
||||
cr_expect(actual == expected);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue