add string + array + scirpt parser
This commit is contained in:
parent
ca043f7b57
commit
dd73b32372
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,3 +2,5 @@
|
||||
build/
|
||||
bin/
|
||||
|
||||
session.vim
|
||||
|
||||
|
2
Makefile
2
Makefile
@ -14,7 +14,7 @@ all: compile_flags.txt dirs scirpt
|
||||
UTILS_SRC = stringmap.c
|
||||
UTILS_OBJ = $(patsubst %.c, build/utils/%.o, $(UTILS_SRC))
|
||||
|
||||
SCIRPT_SRC = main.c lexer.c parser.c
|
||||
SCIRPT_SRC = main.c lexer.c ast.c parser.c
|
||||
SCIRPT_OBJ = $(patsubst %.c, build/scirpt/%.o, $(SCIRPT_SRC))
|
||||
|
||||
scirpt: $(SCIRPT_OBJ) $(UTILS_OBJ)
|
||||
|
28
include/scirpt/ast.h
Normal file
28
include/scirpt/ast.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef SCIRPT_AST_H
|
||||
#define SCIRPT_AST_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
ScirptAstExprTypeEof,
|
||||
ScirptAstExprTypeError,
|
||||
ScirptAstExprTypeId,
|
||||
ScirptAstExprTypeInt,
|
||||
ScirptAstExprTypeString,
|
||||
ScirptAstExprTypeBool,
|
||||
} ScirptAstExprType;
|
||||
|
||||
typedef struct {
|
||||
ScirptAstExprType type;
|
||||
union {
|
||||
char* id_value;
|
||||
int64_t int_value;
|
||||
char* string_value;
|
||||
bool bool_value;
|
||||
};
|
||||
} ScirptAstExpr;
|
||||
|
||||
void scirpt_ast_expr_delete(ScirptAstExpr* expr);
|
||||
|
||||
#endif
|
@ -1,4 +1,29 @@
|
||||
#ifndef SCIRPT_PARSER_H
|
||||
#define SCIRPT_PARSER_H
|
||||
|
||||
#include "scirpt/ast.h"
|
||||
#include "scirpt/lexer.h"
|
||||
#include "utils/generic_array.h"
|
||||
#include "utils/string.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
HeapString message;
|
||||
ScirptPosition pos;
|
||||
} ScirptParserError;
|
||||
|
||||
GENERIC_ARRAY(
|
||||
ScirptParserError, ScirptParserErrorArray, scirpt_parser_error_array
|
||||
)
|
||||
typedef struct ScirptParserErrorArray ScirptParserErrorArray;
|
||||
|
||||
typedef struct ScirptParser ScirptParser;
|
||||
|
||||
ScirptParser*
|
||||
scirpt_parser_new(const char* text, size_t text_length, ScirptLexer* lexer);
|
||||
void scirpt_parser_delete(ScirptParser* parser);
|
||||
ScirptAstExpr* scirpt_parser_next_expr(ScirptParser* parser);
|
||||
bool scirpt_parser_ok(const ScirptParser* parser);
|
||||
const ScirptParserErrorArray* scirpt_parser_errors(const ScirptParser* parser);
|
||||
|
||||
#endif
|
||||
|
@ -7,6 +7,8 @@
|
||||
typedef enum {
|
||||
ScirptTokenTypeEof,
|
||||
ScirptTokenTypeInvalidChar,
|
||||
ScirptTokenTypeMalformedComment,
|
||||
ScirptTokenTypeMalformedString,
|
||||
ScirptTokenTypeId,
|
||||
ScirptTokenTypeInt,
|
||||
ScirptTokenTypeString,
|
||||
@ -21,11 +23,29 @@ typedef enum {
|
||||
ScirptTokenTypeColon,
|
||||
ScirptTokenTypeSemicolon,
|
||||
ScirptTokenTypePlus,
|
||||
ScirptTokenTypePlusEqual,
|
||||
ScirptTokenTypeMinus,
|
||||
ScirptTokenTypeMinusEqual,
|
||||
ScirptTokenTypeAsterisk,
|
||||
ScirptTokenTypeAsteriskEqual,
|
||||
ScirptTokenTypeSlash,
|
||||
ScirptTokenTypeSlashEqual,
|
||||
ScirptTokenTypePercent,
|
||||
ScirptTokenTypePercentEqual,
|
||||
ScirptTokenTypeEqual,
|
||||
ScirptTokenTypeEqualEqual,
|
||||
ScirptTokenTypeExclamation,
|
||||
ScirptTokenTypeExclamationEqual,
|
||||
ScirptTokenTypeLt,
|
||||
ScirptTokenTypeLtEqual,
|
||||
ScirptTokenTypeGt,
|
||||
ScirptTokenTypeGtEqual,
|
||||
ScirptTokenTypeNull,
|
||||
ScirptTokenTypeFalse,
|
||||
ScirptTokenTypeTrue,
|
||||
ScirptTokenTypeNot,
|
||||
ScirptTokenTypeAnd,
|
||||
ScirptTokenTypeOr,
|
||||
ScirptTokenTypeLet,
|
||||
ScirptTokenTypeIf,
|
||||
ScirptTokenTypeElse,
|
||||
|
61
include/utils/generic_array.h
Normal file
61
include/utils/generic_array.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef UTILS_GENERIC_ARRAY_H
|
||||
#define UTILS_GENERIC_ARRAY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define GENERIC_ARRAY(Type, struct_name, function_prefix) \
|
||||
struct struct_name { \
|
||||
Type* data; \
|
||||
size_t length, capacity; \
|
||||
}; \
|
||||
\
|
||||
static inline void function_prefix##_construct(struct struct_name* array) \
|
||||
{ \
|
||||
*array = (struct struct_name) { \
|
||||
.data = NULL, \
|
||||
.length = 0, \
|
||||
.capacity = 0, \
|
||||
}; \
|
||||
} \
|
||||
\
|
||||
static inline void function_prefix##_destroy(struct struct_name* array) \
|
||||
{ \
|
||||
if (array->data) \
|
||||
free(array->data); \
|
||||
} \
|
||||
\
|
||||
static inline size_t function_prefix##_length( \
|
||||
const struct struct_name* array \
|
||||
) \
|
||||
{ \
|
||||
return array->length; \
|
||||
} \
|
||||
\
|
||||
static inline Type* function_prefix##_get( \
|
||||
const struct struct_name* array, size_t index \
|
||||
) \
|
||||
{ \
|
||||
if (index >= array->length) \
|
||||
return NULL; \
|
||||
else \
|
||||
return &array->data[index]; \
|
||||
} \
|
||||
\
|
||||
static inline void function_prefix##_append( \
|
||||
struct struct_name* array, Type value \
|
||||
) \
|
||||
{ \
|
||||
if (array->data == NULL) { \
|
||||
array->capacity = 8; \
|
||||
array->data = malloc(sizeof(Type) * array->capacity); \
|
||||
} else if (array->length == array->capacity) { \
|
||||
array->capacity *= 2; \
|
||||
array->data \
|
||||
= realloc(array->data, sizeof(Type) * array->capacity); \
|
||||
} \
|
||||
array->data[array->length] = value; \
|
||||
array->length++; \
|
||||
}
|
||||
|
||||
#endif
|
21
include/utils/math.h
Normal file
21
include/utils/math.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef UTILS_MATH_H
|
||||
#define UTILS_MATH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// https://stackoverflow.com/questions/466204/rounding-up-to-next-power-of-2
|
||||
// https://stackoverflow.com/questions/1322510/given-an-integer-how-do-i-find-the-next-largest-power-of-two-using-bit-twiddlin/1322548#1322548
|
||||
static inline uint64_t utils_nearest_bigger_power_of_2_u64(uint64_t value)
|
||||
{
|
||||
value--;
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
value |= value >> 32;
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif
|
37
include/utils/string.h
Normal file
37
include/utils/string.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef UTILS_STRING_H
|
||||
#define UTILS_STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
const char* data;
|
||||
size_t length;
|
||||
} StringView;
|
||||
|
||||
typedef struct {
|
||||
char* data;
|
||||
size_t length;
|
||||
} HeapString;
|
||||
|
||||
static inline HeapString heapstring_from(const char* text, size_t length)
|
||||
{
|
||||
char* allocated = malloc(sizeof(char) * length + 1);
|
||||
strncpy(allocated, text, length);
|
||||
HeapString string = {
|
||||
.data = allocated,
|
||||
.length = length,
|
||||
};
|
||||
return string;
|
||||
}
|
||||
static inline HeapString heapstring_from_cstring(const char* text)
|
||||
{
|
||||
return heapstring_from(text, strlen(text));
|
||||
}
|
||||
static inline void heapstring_destroy(HeapString* string)
|
||||
{
|
||||
free(string->data);
|
||||
}
|
||||
|
||||
#endif
|
38
include/utils/string_array.h
Normal file
38
include/utils/string_array.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef UTILS_STRING_ARRAY_H
|
||||
#define UTILS_STRING_ARRAY_H
|
||||
|
||||
#include "utils/generic_array.h"
|
||||
#include "utils/string.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
GENERIC_ARRAY(StringView, StringViewArray, stringview_array)
|
||||
typedef struct StringViewArray StringViewArray;
|
||||
|
||||
static inline StringViewArray* stringview_array_new(void)
|
||||
{
|
||||
StringViewArray* array = malloc(sizeof(StringViewArray));
|
||||
stringview_array_construct(array);
|
||||
return array;
|
||||
}
|
||||
static inline void stringview_array_delete(StringViewArray* array)
|
||||
{
|
||||
stringview_array_destroy(array);
|
||||
free(array);
|
||||
}
|
||||
|
||||
GENERIC_ARRAY(HeapString, HeapStringArray, heapstring_array)
|
||||
typedef struct HeapStringArray HeapStringArray;
|
||||
|
||||
static inline HeapStringArray* heapstring_array_new(void)
|
||||
{
|
||||
HeapStringArray* array = malloc(sizeof(HeapStringArray));
|
||||
heapstring_array_construct(array);
|
||||
return array;
|
||||
}
|
||||
static inline void heapstring_array_delete(HeapStringArray* array)
|
||||
{
|
||||
heapstring_array_destroy(array);
|
||||
free(array);
|
||||
}
|
||||
|
||||
#endif
|
@ -3,26 +3,11 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// https://stackoverflow.com/questions/466204/rounding-up-to-next-power-of-2
|
||||
// https://stackoverflow.com/questions/1322510/given-an-integer-how-do-i-find-the-next-largest-power-of-two-using-bit-twiddlin/1322548#1322548
|
||||
static inline uint64_t utils_nearest_bigger_power_of_2_u64(uint64_t value)
|
||||
{
|
||||
value--;
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
value |= value >> 32;
|
||||
value++;
|
||||
return value;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/7666509/hash-function-for-string
|
||||
// http://www.cse.yorku.ca/~oz/hash.html
|
||||
static inline size_t string_hash_djb2(const unsigned char* value, size_t length)
|
||||
static inline size_t
|
||||
utils_string_hash_djb2(const unsigned char* value, size_t length)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
for (size_t i = 0; i < length && value[i] != '\0'; ++i)
|
||||
@ -44,5 +29,6 @@ void stringmap_remove(StringMap* map, const char* key, size_t key_length);
|
||||
void stringmap_clean(StringMap* map);
|
||||
void stringmap_shrink(StringMap* map);
|
||||
void stringmap_clean_and_shrink(StringMap* map);
|
||||
size_t stringmap_length(StringMap* map);
|
||||
|
||||
#endif
|
||||
|
22
scirpt/ast.c
Normal file
22
scirpt/ast.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include "scirpt/ast.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void scirpt_ast_expr_delete(ScirptAstExpr* expr)
|
||||
{
|
||||
switch (expr->type) {
|
||||
case ScirptAstExprTypeEof:
|
||||
break;
|
||||
case ScirptAstExprTypeError:
|
||||
break;
|
||||
case ScirptAstExprTypeId:
|
||||
free(expr->id_value);
|
||||
break;
|
||||
case ScirptAstExprTypeInt:
|
||||
break;
|
||||
case ScirptAstExprTypeString:
|
||||
free(expr->string_value);
|
||||
break;
|
||||
case ScirptAstExprTypeBool:
|
||||
break;
|
||||
}
|
||||
}
|
228
scirpt/lexer.c
228
scirpt/lexer.c
@ -6,6 +6,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TT(type) ScirptTokenType##type
|
||||
|
||||
static inline void step(ScirptLexer* lexer) { scirpt_lexer_step(lexer); }
|
||||
static inline ScirptToken
|
||||
token(const ScirptLexer* lexer, ScirptTokenType type, ScirptPosition start)
|
||||
@ -49,18 +51,21 @@ void scirpt_lexer_create(
|
||||
)
|
||||
{
|
||||
StringMap* keywords = stringmap_new();
|
||||
add_keyword(keywords, "null", ScirptTokenTypeNull);
|
||||
add_keyword(keywords, "false", ScirptTokenTypeFalse);
|
||||
add_keyword(keywords, "true", ScirptTokenTypeTrue);
|
||||
add_keyword(keywords, "let", ScirptTokenTypeLet);
|
||||
add_keyword(keywords, "if", ScirptTokenTypeIf);
|
||||
add_keyword(keywords, "else", ScirptTokenTypeElse);
|
||||
add_keyword(keywords, "while", ScirptTokenTypeWhile);
|
||||
add_keyword(keywords, "for", ScirptTokenTypeFor);
|
||||
add_keyword(keywords, "in", ScirptTokenTypeIn);
|
||||
add_keyword(keywords, "break", ScirptTokenTypeBreak);
|
||||
add_keyword(keywords, "fn", ScirptTokenTypeFn);
|
||||
add_keyword(keywords, "return", ScirptTokenTypeReturn);
|
||||
add_keyword(keywords, "null", TT(Null));
|
||||
add_keyword(keywords, "false", TT(False));
|
||||
add_keyword(keywords, "true", TT(True));
|
||||
add_keyword(keywords, "not", TT(Not));
|
||||
add_keyword(keywords, "and", TT(And));
|
||||
add_keyword(keywords, "or", TT(Or));
|
||||
add_keyword(keywords, "let", TT(Let));
|
||||
add_keyword(keywords, "if", TT(If));
|
||||
add_keyword(keywords, "else", TT(Else));
|
||||
add_keyword(keywords, "while", TT(While));
|
||||
add_keyword(keywords, "for", TT(For));
|
||||
add_keyword(keywords, "in", TT(In));
|
||||
add_keyword(keywords, "break", TT(Break));
|
||||
add_keyword(keywords, "fn", TT(Fn));
|
||||
add_keyword(keywords, "return", TT(Return));
|
||||
*lexer = (ScirptLexer) {
|
||||
.text = text,
|
||||
.text_length = text_length,
|
||||
@ -99,27 +104,196 @@ static inline bool is_id_char(char value)
|
||||
|
||||
ScirptToken scirpt_lexer_next(ScirptLexer* lexer)
|
||||
{
|
||||
if (done(lexer)) {
|
||||
return token(lexer, ScirptTokenTypeEof, pos(lexer));
|
||||
} else if (is_whitespace(current(lexer))) {
|
||||
return scirpt_lexer_level_1(lexer);
|
||||
}
|
||||
|
||||
ScirptToken scirpt_lexer_level_1(ScirptLexer* lexer)
|
||||
{
|
||||
if (done(lexer))
|
||||
return token(lexer, TT(Eof), pos(lexer));
|
||||
else if (is_whitespace(current(lexer)))
|
||||
return scirpt_lexer_skip_whitespace(lexer);
|
||||
else if (is_id_char_excluding_numbers(current(lexer)))
|
||||
return scirpt_lexer_id_token(lexer);
|
||||
else
|
||||
return scirpt_lexer_level_2(lexer);
|
||||
}
|
||||
|
||||
static inline ScirptToken single_token(ScirptLexer* lexer, ScirptTokenType type)
|
||||
{
|
||||
ScirptPosition start = pos(lexer);
|
||||
step(lexer);
|
||||
return token(lexer, type, start);
|
||||
}
|
||||
|
||||
static inline ScirptToken single_or_double_token(
|
||||
ScirptLexer* lexer,
|
||||
ScirptTokenType first_type,
|
||||
char second_char,
|
||||
ScirptTokenType second_type
|
||||
)
|
||||
{
|
||||
ScirptPosition start = pos(lexer);
|
||||
step(lexer);
|
||||
if (current_is(lexer, second_char)) {
|
||||
step(lexer);
|
||||
while (!done(lexer) && is_whitespace(current(lexer)))
|
||||
return token(lexer, second_type, start);
|
||||
} else {
|
||||
return token(lexer, first_type, start);
|
||||
}
|
||||
}
|
||||
|
||||
ScirptToken scirpt_lexer_level_2(ScirptLexer* lexer)
|
||||
{
|
||||
switch (current(lexer)) {
|
||||
case '0':
|
||||
return single_token(lexer, TT(Int));
|
||||
case '"':
|
||||
return scirpt_lexer_string_token(lexer);
|
||||
case '(':
|
||||
return single_token(lexer, TT(LParen));
|
||||
case ')':
|
||||
return single_token(lexer, TT(RParen));
|
||||
case '{':
|
||||
return single_token(lexer, TT(LBrace));
|
||||
case '}':
|
||||
return single_token(lexer, TT(RBrace));
|
||||
case '[':
|
||||
return single_token(lexer, TT(LBracket));
|
||||
case ']':
|
||||
return single_token(lexer, TT(RBracket));
|
||||
case '.':
|
||||
return single_token(lexer, TT(RBracket));
|
||||
case ',':
|
||||
return single_token(lexer, TT(RBracket));
|
||||
case ':':
|
||||
return single_token(lexer, TT(RBracket));
|
||||
case ';':
|
||||
return single_token(lexer, TT(RBracket));
|
||||
case '+':
|
||||
return single_or_double_token(lexer, TT(Plus), '=', TT(PlusEqual));
|
||||
case '-':
|
||||
return single_or_double_token(
|
||||
lexer, TT(Minus), '=', TT(MinusEqual)
|
||||
);
|
||||
case '*':
|
||||
return single_or_double_token(
|
||||
lexer, TT(Asterisk), '=', TT(AsteriskEqual)
|
||||
);
|
||||
case '/':
|
||||
return single_token(lexer, TT(RBracket));
|
||||
case '%':
|
||||
return single_or_double_token(
|
||||
lexer, TT(Percent), '=', TT(PercentEqual)
|
||||
);
|
||||
case '=':
|
||||
return single_or_double_token(
|
||||
lexer, TT(Equal), '=', TT(EqualEqual)
|
||||
);
|
||||
case '!':
|
||||
return single_or_double_token(
|
||||
lexer, TT(Exclamation), '=', TT(ExclamationEqual)
|
||||
);
|
||||
case '<':
|
||||
return single_or_double_token(lexer, TT(Lt), '=', TT(LtEqual));
|
||||
case '>':
|
||||
return single_or_double_token(lexer, TT(Gt), '=', TT(GtEqual));
|
||||
default:
|
||||
return scirpt_lexer_level_3(lexer);
|
||||
}
|
||||
}
|
||||
|
||||
ScirptToken scirpt_lexer_level_3(ScirptLexer* lexer)
|
||||
{
|
||||
if (is_int_char(current(lexer)))
|
||||
return scirpt_lexer_int_token(lexer);
|
||||
else
|
||||
return single_token(lexer, TT(InvalidChar));
|
||||
}
|
||||
|
||||
ScirptToken scirpt_lexer_skip_whitespace(ScirptLexer* lexer)
|
||||
{
|
||||
step(lexer);
|
||||
while (!done(lexer) && is_whitespace(current(lexer)))
|
||||
step(lexer);
|
||||
return scirpt_lexer_next(lexer);
|
||||
}
|
||||
|
||||
ScirptToken scirpt_lexer_id_token(ScirptLexer* lexer)
|
||||
{
|
||||
ScirptPosition start = pos(lexer);
|
||||
step(lexer);
|
||||
while (!done(lexer) && is_id_char(current(lexer)))
|
||||
step(lexer);
|
||||
size_t* found_keyword = stringmap_get(
|
||||
lexer->keywords, &lexer->text[start.index], lexer->index - start.index
|
||||
);
|
||||
if (found_keyword)
|
||||
return token(lexer, (ScirptTokenType)*found_keyword, start);
|
||||
else
|
||||
return token(lexer, TT(Id), start);
|
||||
}
|
||||
|
||||
ScirptToken scirpt_lexer_int_token(ScirptLexer* lexer)
|
||||
{
|
||||
ScirptPosition start = pos(lexer);
|
||||
step(lexer);
|
||||
while (!done(lexer) && is_int_char(current(lexer)))
|
||||
step(lexer);
|
||||
return token(lexer, TT(Int), start);
|
||||
}
|
||||
|
||||
ScirptToken scirpt_lexer_string_token(ScirptLexer* lexer)
|
||||
{
|
||||
ScirptPosition start = pos(lexer);
|
||||
step(lexer);
|
||||
while (!done(lexer) && current(lexer) != '\"') {
|
||||
char first = current(lexer);
|
||||
step(lexer);
|
||||
if (!done(lexer) && first == '\\')
|
||||
step(lexer);
|
||||
}
|
||||
if (!current_is(lexer, '"'))
|
||||
return token(lexer, TT(MalformedString), start);
|
||||
step(lexer);
|
||||
return token(lexer, TT(String), start);
|
||||
}
|
||||
|
||||
ScirptToken scirpt_lexer_slash_token(ScirptLexer* lexer)
|
||||
{
|
||||
|
||||
ScirptPosition start = pos(lexer);
|
||||
step(lexer);
|
||||
if (current_is(lexer, TT(Slash))) {
|
||||
step(lexer);
|
||||
while (!done(lexer) && current(lexer) != '\n')
|
||||
step(lexer);
|
||||
return scirpt_lexer_next(lexer);
|
||||
} else if (is_id_char_excluding_numbers(current(lexer))) {
|
||||
ScirptPosition start = pos(lexer);
|
||||
} else if (current_is(lexer, TT(Asterisk))) {
|
||||
step(lexer);
|
||||
while (!done(lexer) && is_id_char(current(lexer)))
|
||||
step(lexer);
|
||||
return token(lexer, ScirptTokenTypeId, start);
|
||||
} else {
|
||||
switch (current(lexer)) {
|
||||
default: {
|
||||
ScirptPosition start = pos(lexer);
|
||||
step(lexer);
|
||||
return token(lexer, ScirptTokenTypeInvalidChar, start);
|
||||
int depth = 0;
|
||||
char last_char = '\0';
|
||||
while (!done(lexer)) {
|
||||
if (last_char == '/' && current(lexer) == '*') {
|
||||
depth++;
|
||||
} else if (last_char == '*' && current(lexer) == '/') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
step(lexer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
last_char = current(lexer);
|
||||
step(lexer);
|
||||
}
|
||||
if (depth != 0)
|
||||
return token(lexer, TT(MalformedComment), start);
|
||||
return scirpt_lexer_next(lexer);
|
||||
} else if (current_is(lexer, TT(Equal))) {
|
||||
step(lexer);
|
||||
return token(lexer, TT(SlashEqual), start);
|
||||
} else {
|
||||
return token(lexer, TT(Slash), start);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,14 @@ void scirpt_lexer_create(
|
||||
ScirptLexer* lexer, const char* text, size_t text_length
|
||||
);
|
||||
void scirpt_lexer_destroy(ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_level_1(ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_level_2(ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_level_3(ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_skip_whitespace(ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_id_token(ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_int_token(ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_string_token(ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_slash_token(ScirptLexer* lexer);
|
||||
void scirpt_lexer_step(ScirptLexer* lexer);
|
||||
ScirptPosition scirpt_lexer_pos(const ScirptLexer* lexer);
|
||||
ScirptToken scirpt_lexer_token(
|
||||
|
@ -1,20 +1,56 @@
|
||||
#include "scirpt/ast.h"
|
||||
#include "scirpt/lexer.h"
|
||||
#include "scirpt/parser.h"
|
||||
#include "scirpt/token.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("hello world\n");
|
||||
|
||||
const char* text = "123 if +";
|
||||
printf("test program = \"\"\"\n%s\n\"\"\"\n", text);
|
||||
|
||||
ScirptLexer* lexer = scirpt_lexer_new(text, strlen(text));
|
||||
while (true) {
|
||||
ScirptToken token = scirpt_lexer_next(lexer);
|
||||
if (token.type == ScirptTokenTypeEof)
|
||||
break;
|
||||
printf("%d\n", token.type);
|
||||
{
|
||||
printf("\n- test lexer\n");
|
||||
ScirptLexer* lexer = scirpt_lexer_new(text, strlen(text));
|
||||
while (true) {
|
||||
ScirptToken token = scirpt_lexer_next(lexer);
|
||||
if (token.type == ScirptTokenTypeEof)
|
||||
break;
|
||||
printf("%d\n", token.type);
|
||||
}
|
||||
scirpt_lexer_delete(lexer);
|
||||
}
|
||||
|
||||
{
|
||||
printf("\n- test lexer + parser\n");
|
||||
ScirptLexer* lexer = scirpt_lexer_new(text, strlen(text));
|
||||
ScirptParser* parser = scirpt_parser_new(text, strlen(text), lexer);
|
||||
while (true) {
|
||||
ScirptAstExpr* expr = scirpt_parser_next_expr(parser);
|
||||
if (expr->type == ScirptAstExprTypeEof) {
|
||||
break;
|
||||
} else if (!scirpt_parser_ok(parser)) {
|
||||
const ScirptParserErrorArray* errors
|
||||
= scirpt_parser_errors(parser);
|
||||
for (size_t i = 0; i < scirpt_parser_error_array_length(errors);
|
||||
++i) {
|
||||
ScirptParserError* error
|
||||
= scirpt_parser_error_array_get(errors, i);
|
||||
printf(
|
||||
"error: %s at %d:%d\n",
|
||||
error->message.data,
|
||||
error->pos.line,
|
||||
error->pos.col
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
printf("%d\n", expr->type);
|
||||
scirpt_ast_expr_delete(expr);
|
||||
}
|
||||
scirpt_parser_delete(parser);
|
||||
}
|
||||
}
|
||||
|
160
scirpt/parser.c
160
scirpt/parser.c
@ -0,0 +1,160 @@
|
||||
#include "scirpt/parser.h"
|
||||
#include "parser.h"
|
||||
#include "scirpt/ast.h"
|
||||
#include "scirpt/lexer.h"
|
||||
#include "scirpt/position.h"
|
||||
#include "scirpt/token.h"
|
||||
#include "utils/string.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TT(type) ScirptTokenType##type
|
||||
|
||||
static inline ScirptAstExpr* alloc_expr(ScirptAstExpr data)
|
||||
{
|
||||
ScirptAstExpr* expr = malloc(sizeof(ScirptAstExpr));
|
||||
*expr = data;
|
||||
return expr;
|
||||
}
|
||||
static inline void
|
||||
error(ScirptParser* parser, HeapString message, ScirptPosition pos)
|
||||
{
|
||||
scirpt_parser_error(parser, message, pos);
|
||||
}
|
||||
static inline ScirptPosition pos(ScirptParser* parser)
|
||||
{
|
||||
return parser->current.pos;
|
||||
}
|
||||
static inline void step(ScirptParser* parser) { scirpt_parser_step(parser); }
|
||||
static inline bool current_is(const ScirptParser* parser, ScirptTokenType type)
|
||||
{
|
||||
return scirpt_parser_current_is(parser, type);
|
||||
}
|
||||
static inline bool done(const ScirptParser* parser)
|
||||
{
|
||||
return scirpt_parser_done(parser);
|
||||
}
|
||||
|
||||
ScirptParser*
|
||||
scirpt_parser_new(const char* text, size_t text_length, ScirptLexer* lexer)
|
||||
{
|
||||
ScirptParser* parser = malloc(sizeof(ScirptParser));
|
||||
scirpt_parser_construct(parser, text, text_length, lexer);
|
||||
return parser;
|
||||
}
|
||||
|
||||
void scirpt_parser_delete(ScirptParser* parser) { free(parser); }
|
||||
|
||||
ScirptAstExpr* scirpt_parser_next_expr(ScirptParser* parser)
|
||||
{
|
||||
if (done(parser)) {
|
||||
return alloc_expr((ScirptAstExpr) {
|
||||
.type = ScirptAstExprTypeEof,
|
||||
});
|
||||
} else {
|
||||
return scirpt_parser_parse_expr(parser);
|
||||
}
|
||||
}
|
||||
|
||||
bool scirpt_parser_ok(const ScirptParser* parser) { return parser->ok; }
|
||||
|
||||
const ScirptParserErrorArray* scirpt_parser_errors(const ScirptParser* parser)
|
||||
{
|
||||
return &parser->errors;
|
||||
}
|
||||
|
||||
void scirpt_parser_construct(
|
||||
ScirptParser* parser,
|
||||
const char* text,
|
||||
size_t text_length,
|
||||
ScirptLexer* lexer
|
||||
)
|
||||
{
|
||||
ScirptParserErrorArray errors;
|
||||
scirpt_parser_error_array_construct(&errors);
|
||||
|
||||
*parser = (ScirptParser) {
|
||||
.text = text,
|
||||
.text_length = text_length,
|
||||
.lexer = lexer,
|
||||
.current = scirpt_lexer_next(lexer),
|
||||
.errors = errors,
|
||||
.ok = true,
|
||||
};
|
||||
}
|
||||
|
||||
void scirpt_parser_destroy(ScirptParser* parser)
|
||||
{
|
||||
scirpt_parser_error_array_construct(&parser->errors);
|
||||
}
|
||||
|
||||
ScirptAstExpr* scirpt_parser_parse_expr(ScirptParser* parser)
|
||||
{
|
||||
return scirpt_parser_parse_operand(parser);
|
||||
}
|
||||
|
||||
ScirptAstExpr* scirpt_parser_parse_operand(ScirptParser* parser)
|
||||
{
|
||||
switch (parser->current.type) {
|
||||
case ScirptTokenTypeInt: {
|
||||
HeapString value_string = heapstring_from(
|
||||
&parser->text[pos(parser).index], parser->current.length
|
||||
);
|
||||
int64_t value = atoll(value_string.data);
|
||||
step(parser);
|
||||
return alloc_expr((ScirptAstExpr) {
|
||||
.type = ScirptAstExprTypeInt,
|
||||
.int_value = value,
|
||||
});
|
||||
}
|
||||
case ScirptTokenTypeEof: {
|
||||
error(
|
||||
parser,
|
||||
heapstring_from_cstring("expected value, got Eof"),
|
||||
pos(parser)
|
||||
);
|
||||
return alloc_expr((ScirptAstExpr) {
|
||||
.type = ScirptAstExprTypeError,
|
||||
});
|
||||
}
|
||||
default: {
|
||||
error(
|
||||
parser, heapstring_from_cstring("expected value"), pos(parser)
|
||||
);
|
||||
step(parser);
|
||||
return alloc_expr((ScirptAstExpr) {
|
||||
.type = ScirptAstExprTypeError,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scirpt_parser_error(
|
||||
ScirptParser* parser, HeapString message, ScirptPosition pos
|
||||
)
|
||||
{
|
||||
if (parser->ok)
|
||||
parser->ok = false;
|
||||
scirpt_parser_error_array_append(
|
||||
&parser->errors,
|
||||
(ScirptParserError) {
|
||||
.message = message,
|
||||
.pos = pos,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void scirpt_parser_step(ScirptParser* parser)
|
||||
{
|
||||
parser->current = scirpt_lexer_next(parser->lexer);
|
||||
}
|
||||
|
||||
bool scirpt_parser_current_is(const ScirptParser* parser, ScirptTokenType type)
|
||||
{
|
||||
return parser->current.type == type;
|
||||
}
|
||||
|
||||
bool scirpt_parser_done(const ScirptParser* parser)
|
||||
{
|
||||
return parser->current.type == ScirptTokenTypeEof;
|
||||
}
|
@ -1,6 +1,37 @@
|
||||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
#include "scirpt/ast.h"
|
||||
#include "scirpt/lexer.h"
|
||||
#include "scirpt/parser.h"
|
||||
#include "scirpt/position.h"
|
||||
#include "scirpt/token.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct ScirptParser {
|
||||
const char* text;
|
||||
size_t text_length;
|
||||
ScirptLexer* lexer;
|
||||
ScirptToken current;
|
||||
ScirptParserErrorArray errors;
|
||||
bool ok;
|
||||
};
|
||||
|
||||
void scirpt_parser_construct(
|
||||
ScirptParser* parser,
|
||||
const char* text,
|
||||
size_t text_length,
|
||||
ScirptLexer* lexer
|
||||
);
|
||||
void scirpt_parser_destroy(ScirptParser* parser);
|
||||
ScirptAstExpr* scirpt_parser_parse_expr(ScirptParser* parser);
|
||||
ScirptAstExpr* scirpt_parser_parse_operand(ScirptParser* parser);
|
||||
void scirpt_parser_error(
|
||||
ScirptParser* parser, HeapString message, ScirptPosition pos
|
||||
);
|
||||
void scirpt_parser_step(ScirptParser* parser);
|
||||
bool scirpt_parser_current_is(const ScirptParser* parser, ScirptTokenType type);
|
||||
bool scirpt_parser_done(const ScirptParser* parser);
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "stringmap.h"
|
||||
#include "utils/math.h"
|
||||
#include "utils/stringmap.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@ -14,18 +15,20 @@ void stringmap_delete(StringMap* map) { free(map); }
|
||||
|
||||
size_t* stringmap_get(const StringMap* map, const char* key, size_t key_length)
|
||||
{
|
||||
size_t key_hash = string_hash_djb2((const unsigned char*)key, key_length);
|
||||
for (size_t i = 0; i < map->size; ++i)
|
||||
if (map->entries[i].key_hash == key_hash && !map->entries[i].deleted)
|
||||
return &map->entries[i].value;
|
||||
size_t key_hash
|
||||
= utils_string_hash_djb2((const unsigned char*)key, key_length);
|
||||
for (size_t i = 0; i < map->length; ++i)
|
||||
if (map->data[i].key_hash == key_hash && !map->data[i].deleted)
|
||||
return &map->data[i].value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool stringmap_has(const StringMap* map, const char* key, size_t key_length)
|
||||
{
|
||||
size_t key_hash = string_hash_djb2((const unsigned char*)key, key_length);
|
||||
for (size_t i = 0; i < map->size; ++i)
|
||||
if (map->entries[i].key_hash == key_hash && !map->entries[i].deleted)
|
||||
size_t key_hash
|
||||
= utils_string_hash_djb2((const unsigned char*)key, key_length);
|
||||
for (size_t i = 0; i < map->length; ++i)
|
||||
if (map->data[i].key_hash == key_hash && !map->data[i].deleted)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -34,27 +37,27 @@ void stringmap_set(
|
||||
StringMap* map, const char* key, size_t key_length, size_t value
|
||||
)
|
||||
{
|
||||
size_t key_hash = string_hash_djb2((const unsigned char*)key, key_length);
|
||||
for (size_t i = 0; i < map->size; ++i) {
|
||||
if (map->entries[i].key_hash == key_hash && !map->entries[i].deleted) {
|
||||
map->entries[i].value = value;
|
||||
size_t key_hash
|
||||
= utils_string_hash_djb2((const unsigned char*)key, key_length);
|
||||
for (size_t i = 0; i < map->length; ++i) {
|
||||
if (map->data[i].key_hash == key_hash && !map->data[i].deleted) {
|
||||
map->data[i].value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (map->entries == NULL) {
|
||||
if (map->data == NULL) {
|
||||
map->capacity = 8;
|
||||
map->entries = malloc(sizeof(StringMapEntry) * map->capacity);
|
||||
} else if (map->size == map->capacity) {
|
||||
map->data = malloc(sizeof(StringMapEntry) * map->capacity);
|
||||
} else if (map->length == map->capacity) {
|
||||
map->capacity *= 2;
|
||||
map->entries
|
||||
= realloc(map->entries, sizeof(StringMapEntry) * map->capacity);
|
||||
map->data = realloc(map->data, sizeof(StringMapEntry) * map->capacity);
|
||||
}
|
||||
map->entries[map->size] = (StringMapEntry) {
|
||||
map->data[map->length] = (StringMapEntry) {
|
||||
.deleted = false,
|
||||
.key_hash = key_hash,
|
||||
.value = value,
|
||||
};
|
||||
map->size++;
|
||||
map->length++;
|
||||
}
|
||||
|
||||
void stringmap_reserve(StringMap* map, size_t minimum_size)
|
||||
@ -62,16 +65,16 @@ void stringmap_reserve(StringMap* map, size_t minimum_size)
|
||||
if (map->capacity >= minimum_size)
|
||||
return;
|
||||
map->capacity = utils_nearest_bigger_power_of_2_u64(minimum_size);
|
||||
map->entries
|
||||
= realloc(map->entries, sizeof(StringMapEntry) * map->capacity);
|
||||
map->data = realloc(map->data, sizeof(StringMapEntry) * map->capacity);
|
||||
}
|
||||
|
||||
void stringmap_remove(StringMap* map, const char* key, size_t key_length)
|
||||
{
|
||||
size_t key_hash = string_hash_djb2((const unsigned char*)key, key_length);
|
||||
for (size_t i = 0; i < map->size; ++i) {
|
||||
if (map->entries[i].key_hash == key_hash && !map->entries[i].deleted) {
|
||||
map->entries[i].deleted = true;
|
||||
size_t key_hash
|
||||
= utils_string_hash_djb2((const unsigned char*)key, key_length);
|
||||
for (size_t i = 0; i < map->length; ++i) {
|
||||
if (map->data[i].key_hash == key_hash && !map->data[i].deleted) {
|
||||
map->data[i].deleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,21 +82,20 @@ void stringmap_remove(StringMap* map, const char* key, size_t key_length)
|
||||
void stringmap_clean(StringMap* map)
|
||||
{
|
||||
size_t shift_amount = 0;
|
||||
for (size_t i = 0; i < map->size; ++i) {
|
||||
map->entries[i - shift_amount] = map->entries[i];
|
||||
if (map->entries[i].deleted)
|
||||
for (size_t i = 0; i < map->length; ++i) {
|
||||
map->data[i - shift_amount] = map->data[i];
|
||||
if (map->data[i].deleted)
|
||||
shift_amount++;
|
||||
}
|
||||
}
|
||||
|
||||
void stringmap_shrink(StringMap* map)
|
||||
{
|
||||
size_t new_size = utils_nearest_bigger_power_of_2_u64(map->size);
|
||||
size_t new_size = utils_nearest_bigger_power_of_2_u64(map->length);
|
||||
if (new_size >= map->capacity)
|
||||
return;
|
||||
map->capacity = new_size;
|
||||
map->entries
|
||||
= realloc(map->entries, sizeof(StringMapEntry) * map->capacity);
|
||||
map->data = realloc(map->data, sizeof(StringMapEntry) * map->capacity);
|
||||
}
|
||||
|
||||
void stringmap_clean_and_shrink(StringMap* map)
|
||||
@ -102,17 +104,19 @@ void stringmap_clean_and_shrink(StringMap* map)
|
||||
stringmap_shrink(map);
|
||||
}
|
||||
|
||||
size_t stringmap_length(StringMap* map) { return map->length; }
|
||||
|
||||
void stringmap_create(StringMap* map)
|
||||
{
|
||||
*map = (StringMap) {
|
||||
.entries = NULL,
|
||||
.size = 0,
|
||||
.data = NULL,
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
};
|
||||
}
|
||||
|
||||
void stringmap_destroy(StringMap* map)
|
||||
{
|
||||
if (map->entries)
|
||||
free(map->entries);
|
||||
if (map->data)
|
||||
free(map->data);
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ typedef struct StringMapEntry {
|
||||
} StringMapEntry;
|
||||
|
||||
struct StringMap {
|
||||
StringMapEntry* entries;
|
||||
size_t size, capacity;
|
||||
StringMapEntry* data;
|
||||
size_t length, capacity;
|
||||
};
|
||||
|
||||
void stringmap_create(StringMap* map);
|
||||
|
Loading…
Reference in New Issue
Block a user