diff --git a/bin/flup b/bin/flup new file mode 100755 index 0000000..ccbb4a1 Binary files /dev/null and b/bin/flup differ diff --git a/include/utilitiec b/include/utilitiec new file mode 120000 index 0000000..1679026 --- /dev/null +++ b/include/utilitiec @@ -0,0 +1 @@ +/home/vego/Git/utilitiec/src/ \ No newline at end of file diff --git a/lib/utilitiec b/lib/utilitiec new file mode 120000 index 0000000..8945509 --- /dev/null +++ b/lib/utilitiec @@ -0,0 +1 @@ +/home/vego/Git/utilitiec/build/lib/ \ No newline at end of file diff --git a/make.sh b/make.sh new file mode 100644 index 0000000..9f07a21 --- /dev/null +++ b/make.sh @@ -0,0 +1 @@ +gcc `find src/ -name '*.c'` lib/utilitiec/libargumentc.a lib/utilitiec/libdynamicarray.a lib/utilitiec/libpointers.a lib/utilitiec/liballocator-interface.a lib/utilitiec/libStringView.a -lm -ggdb -o bin/flup diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..5527518 --- /dev/null +++ b/src/main.c @@ -0,0 +1,82 @@ +/* + * This code is part of the programming language flup + * flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later. + * Copyright (C) 2024 VegOwOtenks + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "../include/utilitiec/argumentc/argumentc.h" + +char* load_file_string(StringView path) +{ + FILE* stream = fopen(path.source, "r"); + if (stream == NULL) { + fprintf(stderr, "Fatal Error: Failed to open file at %*s\n", (int) path.length, path.source); + return NULL; + } + + if (fseek(stream, 0, SEEK_END)) { + perror("fseek"); + return NULL; + } + + long length = ftell(stream); + if (length == -1) { + perror("ftell"); + return NULL; + } + + rewind(stream); + + char* buffer = malloc(length + 1); + if (buffer == NULL) { + fprintf(stderr, "Fatal Error: Failed to allocate %li bytes\n", length); + return NULL; + } + + size_t bytes_read = fread(buffer, 1, length + 1, stream); + if (bytes_read != length) { + fprintf(stderr, "Fatal Error: Failed read %li bytes from script file, got only %li\n", length, bytes_read); + free(buffer); + return NULL; + } + + fclose(stream); + + return buffer; +} + +int main(int argc, const char* argv []) +{ + Argumentc arguments; + Argumentc_Create(&arguments, argc, argv); + + Option script_file = Argumentc_PopLongArgument(&arguments, StringView_FromString("file")).argument; + if (script_file.type == OPTIONTYPE_NONE) { + fprintf(stderr, "Usage: [program] --file path/to/script_file\n"); + return 1; + } + + char* script_string = load_file_string(script_file.content); + if (script_string == NULL) return 1; + + puts(script_string); + + return EXIT_SUCCESS; +} diff --git a/src/tokenizer.c b/src/tokenizer.c new file mode 100644 index 0000000..ce12bbb --- /dev/null +++ b/src/tokenizer.c @@ -0,0 +1,116 @@ +#include "tokenizer.h" +#include +#include + +static StringView StringViewOfNumberTillNextNonDigit(StringView* source) { + StringView stringViewOfNumber = StringView_Slice(*source, 0, 0); + while (source->length != 0 && isdigit(source->source[0])) { + *source = StringView_Drop(*source, 1); + stringViewOfNumber.length ++; + } + return stringViewOfNumber; +} + +static int64_t* _StringView_FoldInt64(char c, int64_t* i) +{ + *i = *i * 10 + (c - '0'); + return i; +} + +static double* _StringView_FoldDouble(char c, double* d) +{ + *d = *d * 10 + (c - '0'); + return d; +} + +static Token _Tokenizer_ParseInt64(bool negative, StringView integerPart) +{ + int64_t theInt64 = 0; + StringView_FoldLeft(integerPart, &theInt64, (StringViewFoldFunction) _StringView_FoldInt64); + + return (Token) { + .type = TOKENTYPE_INTEGER, + .get = { + .integer = theInt64 * (negative ? -1 : 1) + } + }; +} + +static Token _Tokenizer_ParseDouble(bool negative, StringView integerPart, StringView decimalPart) +{ + double theDouble = 0.0; + StringView_FoldLeft(integerPart, &theDouble, (StringViewFoldFunction) _StringView_FoldDouble); + double theDecimal = 0.0; + StringView_FoldLeft(decimalPart, &theDecimal, (StringViewFoldFunction) _StringView_FoldDouble); + + double result = (negative ? -1 : 1) * (theDouble + theDecimal / pow(10.0, decimalPart.length)); + + return (Token) { + .type = TOKENTYPE_DOUBLE, + .get = { + .decimal = result + } + }; +} + +static Token _Tokenizer_NumberToken(StringView* source) +{ + bool negative = false; + if (StringView_StartsWith(*source, StringView_FromString("-"))) { + negative = true; + *source = StringView_Drop(*source, 1); + } + + StringView integerPart = StringViewOfNumberTillNextNonDigit(source); + bool has_point = false; + if (source->length != 0 && source->source[0] == '.') { + *source = StringView_Drop(*source, 1); + has_point = true; + } + StringView decimalPart = StringViewOfNumberTillNextNonDigit(source); + + if (has_point) { + return _Tokenizer_ParseDouble(negative, integerPart, decimalPart); + } else { + return _Tokenizer_ParseInt64(negative, integerPart); + } +} + +static bool _Tokenizer_IdentifierLetter(char c) +{ + return isalnum(c); +} + +static Token _Tokenizer_IdentifierToken(StringView* source) +{ + StringView identifier = StringView_TakeWhile(*source, _Tokenizer_IdentifierLetter); + *source = StringView_Drop(*source, identifier.length); + + return (Token) { + .type = TOKENTYPE_IDENTIFIER, + .get = { + .identifier = identifier, + } + }; +} + +Token Tokenizer_NextToken(StringView* source) +{ + while (source->length != 0 && isspace(source->source[0])) { + 0[source] = StringView_Slice(*source, 1, source->length); + } + + if (source->length == 0) { + return TOKEN_NONE; + } + + if (isdigit(source->source[0]) || StringView_StartsWith(*source, StringView_FromString("-"))) { + // parse int/double + return _Tokenizer_NumberToken(source); + } else if (isalpha(source->source[0])) { + // parse name + return _Tokenizer_IdentifierToken(source); + } else { + return (Token) {.type = TOKENTYPE_ERROR, .get = {.error = *source } }; + } +} diff --git a/src/tokenizer.h b/src/tokenizer.h new file mode 100644 index 0000000..acf1dc6 --- /dev/null +++ b/src/tokenizer.h @@ -0,0 +1,32 @@ +#ifndef FLUP_TOKENIZER_H +#define FLUP_TOKENIZER_H + +#include "../include/utilitiec/StringView/StringView.h" +#include + +enum TokenType { + TOKENTYPE_NONE, + TOKENTYPE_INTEGER, + TOKENTYPE_DOUBLE, + TOKENTYPE_IDENTIFIER, + TOKENTYPE_ERROR, +}; + +union TokenContent { + StringView identifier; + StringView error; + int64_t integer; + double decimal; +}; + +typedef struct Token_s { + enum TokenType type; + union TokenContent get; +} Token; + + +#define TOKEN_NONE ((Token) {.type = TOKENTYPE_NONE, .get = {.error = STRINGVIEW_NONE } } ) + +Token Tokenizer_NextToken(StringView* source); + +#endif //header guard