Added dynamic strings. They do not yet work.
This commit is contained in:
parent
89e8674ced
commit
8e8b6233d6
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
*.o
|
*.o
|
||||||
*.so
|
*.so
|
||||||
|
tags
|
||||||
*.out
|
*.out
|
||||||
.cache
|
.cache
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
11
Makefile
11
Makefile
@ -11,7 +11,7 @@ TEST_OBJ_DIR = $(TEST_BUILD_DIR)/obj
|
|||||||
|
|
||||||
CC = clang
|
CC = clang
|
||||||
LINK = clang
|
LINK = clang
|
||||||
CFLAGS = -Wall
|
CFLAGS = -Wall -DDBG -ggdb
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
|
|
||||||
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
|
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
|
||||||
@ -28,6 +28,10 @@ WHITE_BOLD = $(RESETCOLOR)\x1b[37;1m
|
|||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
release: clean
|
||||||
|
release: CFLAGS = -Wall -O2
|
||||||
|
release: $(TARGET)
|
||||||
|
|
||||||
# Link to final binary.
|
# Link to final binary.
|
||||||
$(TARGET): $(OBJ_FILES)
|
$(TARGET): $(OBJ_FILES)
|
||||||
@ echo -e "$(WHITE_BOLD)Linking $(WHITE)$(TARGET)$(WHITE_BOLD)...$(RESETCOLOR) $(CC) -o $(TARGET) $(OBJ_FILES) $(LDFLAGS)"
|
@ echo -e "$(WHITE_BOLD)Linking $(WHITE)$(TARGET)$(WHITE_BOLD)...$(RESETCOLOR) $(CC) -o $(TARGET) $(OBJ_FILES) $(LDFLAGS)"
|
||||||
@ -56,5 +60,8 @@ clean:
|
|||||||
@ echo -e "$(WHITE_BOLD)Cleaning up...$(WHITE) $(OBJ_DIR)/*.o $(TEST_OBJ_DIR)/*.o $(TEST_BUILD_DIR)/test.out $(TARGET)$(RESETCOLOR)"
|
@ echo -e "$(WHITE_BOLD)Cleaning up...$(WHITE) $(OBJ_DIR)/*.o $(TEST_OBJ_DIR)/*.o $(TEST_BUILD_DIR)/test.out $(TARGET)$(RESETCOLOR)"
|
||||||
@ rm -rf $(OBJ_DIR)/*.o $(TEST_OBJ_DIR)/*.o $(TEST_BUILD_DIR)/test.out $(TARGET)
|
@ rm -rf $(OBJ_DIR)/*.o $(TEST_OBJ_DIR)/*.o $(TEST_BUILD_DIR)/test.out $(TARGET)
|
||||||
|
|
||||||
.PHONY: all clean test nocolor
|
run:
|
||||||
|
./$(TARGET)
|
||||||
|
|
||||||
|
.PHONY: all clean test nocolor release
|
||||||
|
|
||||||
|
1
examples/test.scl
Normal file
1
examples/test.scl
Normal file
@ -0,0 +1 @@
|
|||||||
|
1 + 1
|
27
src/dstr.c
Normal file
27
src/dstr.c
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "include/dstr.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
Dstr* dstr_init(void) {
|
||||||
|
Dstr* dstr = malloc(sizeof(Dstr));
|
||||||
|
|
||||||
|
dstr->bufsz = DSTR_INITSZ;
|
||||||
|
dstr->buf = malloc(DSTR_INITSZ);
|
||||||
|
dstr->ln = 0;
|
||||||
|
|
||||||
|
return dstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dstr_destroy(Dstr* dstr) {
|
||||||
|
free(dstr->buf);
|
||||||
|
free(dstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dstr_append(Dstr* dest, size_t ln, char* src) {
|
||||||
|
if (dest->ln + ln > dest->bufsz) {
|
||||||
|
// Double the buffer size when overflown.
|
||||||
|
dest->bufsz *= dest->bufsz;
|
||||||
|
dest->buf = realloc(dest->buf, dest->bufsz);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(dest->buf + ln, src);
|
||||||
|
}
|
21
src/include/dstr.h
Normal file
21
src/include/dstr.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef DSTR_H
|
||||||
|
#define DSTR_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DSTR_INITSZ 128
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* buf; // The buffer containing the string.
|
||||||
|
size_t bufsz; // The size of the buffer.
|
||||||
|
size_t ln; // The number of characters in the buffer.
|
||||||
|
} Dstr;
|
||||||
|
|
||||||
|
Dstr* dstr_init(void);
|
||||||
|
void dstr_destroy(Dstr* dstr);
|
||||||
|
|
||||||
|
// Append ln characters of src to dest.
|
||||||
|
void dstr_append(Dstr* dest, size_t ln, char* src);
|
||||||
|
|
||||||
|
#endif
|
@ -4,7 +4,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
|
||||||
#define TOKENS_MAX 32
|
#define TOKENS_MAX 32
|
||||||
@ -52,9 +55,4 @@ void lexer_inc(Lexer* lexer);
|
|||||||
// Add a token to the lexer.
|
// Add a token to the lexer.
|
||||||
void lexer_add_token(Lexer* lexer, Token* token);
|
void lexer_add_token(Lexer* lexer, Token* token);
|
||||||
|
|
||||||
// Print the contents of a lexer.
|
|
||||||
void lexer_print(Lexer* lexer);
|
|
||||||
|
|
||||||
static char* lexer_state_str(Lexer* lexer);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,7 +19,10 @@ typedef struct {
|
|||||||
Token* token_init(TokenType type, char* val);
|
Token* token_init(TokenType type, char* val);
|
||||||
void token_destroy(Token* token);
|
void token_destroy(Token* token);
|
||||||
|
|
||||||
void token_print(Token* token);
|
// Returns a string representation of the Token.
|
||||||
static char* token_type_str(Token* token);
|
char* token_to_str(Token* token, unsigned int indent);
|
||||||
|
|
||||||
|
// Returns a string representation of the TokenType.
|
||||||
|
char* token_type_to_str(TokenType t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
int is_even(int n);
|
#ifdef DBG
|
||||||
|
#define log_dbg(msg) \
|
||||||
|
printf("[dbg:%s:%s:%d] %s\n", __FILE__, __func__, __LINE__, msg); \
|
||||||
|
fflush(stdout);
|
||||||
|
#else
|
||||||
|
#define log_dbg(msg)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
38
src/lexer.c
38
src/lexer.c
@ -1,9 +1,5 @@
|
|||||||
#include "include/lexer.h"
|
#include "include/lexer.h"
|
||||||
#include "include/token.h"
|
#include "include/util.h"
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
Lexer* lexer_init(char* src) {
|
Lexer* lexer_init(char* src) {
|
||||||
Lexer* lexer = malloc(sizeof(Lexer));
|
Lexer* lexer = malloc(sizeof(Lexer));
|
||||||
@ -12,7 +8,7 @@ Lexer* lexer_init(char* src) {
|
|||||||
lexer->srcl = strlen(src);
|
lexer->srcl = strlen(src);
|
||||||
lexer->cchar = lexer->src;
|
lexer->cchar = lexer->src;
|
||||||
|
|
||||||
lexer->tokens = calloc(TOKENS_MAX, sizeof(Token));
|
lexer->tokens = calloc(TOKENS_MAX, sizeof(Token*));
|
||||||
lexer->ntokens = 0;
|
lexer->ntokens = 0;
|
||||||
lexer->state = LEXER_STATE_CONFUSED;
|
lexer->state = LEXER_STATE_CONFUSED;
|
||||||
|
|
||||||
@ -22,7 +18,7 @@ Lexer* lexer_init(char* src) {
|
|||||||
void lexer_destroy(Lexer* lexer) {
|
void lexer_destroy(Lexer* lexer) {
|
||||||
free(lexer->src);
|
free(lexer->src);
|
||||||
|
|
||||||
for (int i = 0; i < lexer->ntokens; token_destroy(lexer->tokens[i++]));
|
for (int i = 0; i < lexer->ntokens; i++) token_destroy(lexer->tokens[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_lex(Lexer* lexer) {
|
void lexer_lex(Lexer* lexer) {
|
||||||
@ -37,11 +33,13 @@ void lexer_lex(Lexer* lexer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void lexer_do_confused(Lexer* lexer) {
|
void lexer_do_confused(Lexer* lexer) {
|
||||||
|
log_dbg("entered confused mode");
|
||||||
if (isdigit(*lexer->cchar)) lexer_do_number(lexer);
|
if (isdigit(*lexer->cchar)) lexer_do_number(lexer);
|
||||||
else lexer_do_call(lexer);
|
else lexer_do_call(lexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_do_number(Lexer* lexer) {
|
void lexer_do_number(Lexer* lexer) {
|
||||||
|
log_dbg("entered number mode");
|
||||||
// Size of the number string.
|
// Size of the number string.
|
||||||
size_t numsz;
|
size_t numsz;
|
||||||
|
|
||||||
@ -59,6 +57,7 @@ void lexer_do_number(Lexer* lexer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void lexer_do_call(Lexer* lexer) {
|
void lexer_do_call(Lexer* lexer) {
|
||||||
|
log_dbg("entered call mode");
|
||||||
// Size of the call string.
|
// Size of the call string.
|
||||||
size_t callsz;
|
size_t callsz;
|
||||||
|
|
||||||
@ -71,6 +70,8 @@ void lexer_do_call(Lexer* lexer) {
|
|||||||
char* call = malloc(callsz + 1);
|
char* call = malloc(callsz + 1);
|
||||||
memcpy(call, start, callsz);
|
memcpy(call, start, callsz);
|
||||||
call[callsz] = '\0';
|
call[callsz] = '\0';
|
||||||
|
|
||||||
|
lexer_add_token(lexer, token_init(TOKEN_TYPE_CALL, call));
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_inc(Lexer* lexer) {
|
void lexer_inc(Lexer* lexer) {
|
||||||
@ -81,29 +82,8 @@ void lexer_add_token(Lexer* lexer, Token* token) {
|
|||||||
assert(lexer->ntokens < TOKENS_MAX);
|
assert(lexer->ntokens < TOKENS_MAX);
|
||||||
|
|
||||||
if (lexer->ntokens < TOKENS_MAX - 1) {
|
if (lexer->ntokens < TOKENS_MAX - 1) {
|
||||||
lexer->tokens[lexer->ntokens - 1] = token;
|
lexer->tokens[lexer->ntokens] = token;
|
||||||
lexer->ntokens++;
|
lexer->ntokens++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_print(Lexer* lexer) {
|
|
||||||
printf("Lexer @%p:\n", lexer);
|
|
||||||
printf("\tsrc: \"%s\"\n", lexer->src);
|
|
||||||
printf("\tsrcl: \"%ld\"\n", lexer->srcl);
|
|
||||||
printf("\tcchar: \"%s\"\n", lexer->cchar);
|
|
||||||
printf("\tntokens: %ld\n", lexer->ntokens);
|
|
||||||
printf("\ttokens: [START]\n");
|
|
||||||
for (int i = 0; i < lexer->ntokens; i++) token_print(lexer->tokens[i]);
|
|
||||||
printf("[END]\n");
|
|
||||||
printf("\tstate: %s\n", lexer_state_str(lexer));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* lexer_state_str(Lexer* lexer) {
|
|
||||||
switch (lexer->state) {
|
|
||||||
case LEXER_STATE_NUM: return "NUM";
|
|
||||||
case LEXER_STATE_CALL: return "CALL";
|
|
||||||
case LEXER_STATE_CONFUSED: return "CONFUSED";
|
|
||||||
default: return "???";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "include/token.h"
|
||||||
#include "include/util.h"
|
#include "include/util.h"
|
||||||
#include "include/lexer.h"
|
#include "include/lexer.h"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
char* text = malloc(5);
|
char* text = malloc(5);
|
||||||
text = "a1b2";
|
text = "aa11";
|
||||||
|
|
||||||
Lexer* lexer = lexer_init(text);
|
Lexer* lexer = lexer_init(text);
|
||||||
lexer_print(lexer);
|
|
||||||
lexer_lex(lexer);
|
lexer_lex(lexer);
|
||||||
lexer_print(lexer);
|
|
||||||
|
printf("%s\n", token_to_str(lexer->tokens[0], 0));
|
||||||
|
|
||||||
|
lexer_destroy(lexer);
|
||||||
}
|
}
|
||||||
|
18
src/token.c
18
src/token.c
@ -1,4 +1,5 @@
|
|||||||
#include "include/token.h"
|
#include "include/token.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
Token* token_init(TokenType type, char* val) {
|
Token* token_init(TokenType type, char* val) {
|
||||||
Token* t = malloc(sizeof(Token));
|
Token* t = malloc(sizeof(Token));
|
||||||
@ -14,17 +15,8 @@ void token_destroy(Token* t) {
|
|||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void token_print(Token* token) {
|
char* token_to_str(Token* token, unsigned int indent) {
|
||||||
printf("Token @%p:\n", token);
|
char* title = malloc(sizeof("Token @ 0x000000000000\n"));
|
||||||
printf("\ttype: %s\n", token_type_str(token));
|
sprintf(title, "Token @%p\n", token);
|
||||||
printf("\tval: %s\n", token->val);
|
return title;
|
||||||
printf("\tlen: %ld\n", token->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* token_type_str(Token* token) {
|
|
||||||
switch (token->type) {
|
|
||||||
case TOKEN_TYPE_CALL: return "CALL";
|
|
||||||
case TOKEN_TYPE_NUMBER: return "NUMBER";
|
|
||||||
default: return "???";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1 @@
|
|||||||
#include "include/util.h"
|
#include "include/util.h"
|
||||||
|
|
||||||
int is_even(int n) { return !(n % 2); }
|
|
||||||
|
37
test/dstr.c
Normal file
37
test/dstr.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "../src/include/dstr.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "registry.h"
|
||||||
|
|
||||||
|
void test_dstr_init() {
|
||||||
|
Dstr* dstr = dstr_init();
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(DSTR_INITSZ, dstr->bufsz);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(malloc(DSTR_INITSZ), dstr->buf);
|
||||||
|
TEST_ASSERT_EQUAL_size_t(0, dstr->ln);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_dstr_append() {
|
||||||
|
char* str1 = malloc(2);
|
||||||
|
str1 = "h";
|
||||||
|
|
||||||
|
char* str2 = malloc(DSTR_INITSZ);
|
||||||
|
str2 = "h";
|
||||||
|
|
||||||
|
|
||||||
|
Dstr* dstr = dstr_init();
|
||||||
|
dstr_append(dstr, 1, str1);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(str2, dstr->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_dstr() {
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(test_dstr_init);
|
||||||
|
RUN_TEST(test_dstr_append);
|
||||||
|
UNITY_END();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor)) void register_dstr() {
|
||||||
|
register_test(test_dstr);
|
||||||
|
}
|
52
test/lexer.c
Normal file
52
test/lexer.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include "../src/include/lexer.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "registry.h"
|
||||||
|
|
||||||
|
void test_lexer_init() {
|
||||||
|
char* src = malloc(sizeof("a1b2"));
|
||||||
|
src = "a1b2";
|
||||||
|
Lexer* lexer = lexer_init(src);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(src, lexer->src);
|
||||||
|
TEST_ASSERT_EQUAL_INT(4, lexer->srcl);
|
||||||
|
TEST_ASSERT_EQUAL_CHAR(src[0], *lexer->cchar);
|
||||||
|
TEST_ASSERT_EQUAL_INT(LEXER_STATE_CONFUSED, lexer->state);
|
||||||
|
// Hope that token arr. is right size :).
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, lexer->ntokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_lexer_lex_callnum() {
|
||||||
|
char* src = malloc(sizeof("a1b2"));
|
||||||
|
src = "a1b2";
|
||||||
|
Lexer* lexer = lexer_init(src);
|
||||||
|
|
||||||
|
Token* tokens[4] = {
|
||||||
|
token_init(TOKEN_TYPE_CALL, "a"),
|
||||||
|
token_init(TOKEN_TYPE_NUMBER, "1"),
|
||||||
|
token_init(TOKEN_TYPE_CALL, "b"),
|
||||||
|
token_init(TOKEN_TYPE_NUMBER, "2"),
|
||||||
|
};
|
||||||
|
|
||||||
|
lexer_lex(lexer);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(4, lexer->ntokens);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
printf("h");
|
||||||
|
fflush(stdout);
|
||||||
|
TEST_ASSERT_EQUAL_INT(tokens[i]->type, lexer->tokens[i]->type);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(tokens[i]->val, lexer->tokens[i]->val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_lexer() {
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(test_lexer_init);
|
||||||
|
RUN_TEST(test_lexer_lex_callnum);
|
||||||
|
UNITY_END();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor)) void register_lexer() {
|
||||||
|
register_test(test_lexer);
|
||||||
|
}
|
18
test/util.c
18
test/util.c
@ -1,18 +0,0 @@
|
|||||||
#include "../src/include/util.h"
|
|
||||||
#include "registry.h"
|
|
||||||
#include "unity/unity.h"
|
|
||||||
|
|
||||||
void test_is_even() {
|
|
||||||
TEST_ASSERT_EQUAL(0, is_even(1));;
|
|
||||||
TEST_ASSERT_EQUAL(1, is_even(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
int test_util() {
|
|
||||||
UNITY_BEGIN();
|
|
||||||
RUN_TEST(test_is_even);
|
|
||||||
return UNITY_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((constructor)) void register_tests_util() {
|
|
||||||
register_test(test_util);
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user