Compare commits
No commits in common. "8e8b6233d69298202ee9e22b15df378d78cde097" and "77f40cf3c59a735ac7a8157cf33df6cb803b42ad" have entirely different histories.
8e8b6233d6
...
77f40cf3c5
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,5 @@
|
|||||||
*.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 -DDBG -ggdb
|
CFLAGS = -Wall
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
|
|
||||||
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
|
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
|
||||||
@ -28,10 +28,6 @@ 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)"
|
||||||
@ -60,8 +56,5 @@ 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)
|
||||||
|
|
||||||
run:
|
.PHONY: all clean test nocolor
|
||||||
./$(TARGET)
|
|
||||||
|
|
||||||
.PHONY: all clean test nocolor release
|
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# SCL: Simple Calculator Language
|
# SCL: Simple Calculator Language
|
||||||
|
|
||||||
A spiritual successor to halk.
|
A rewrite of halk.
|
||||||
|
@ -1 +0,0 @@
|
|||||||
1 + 1
|
|
27
src/dstr.c
27
src/dstr.c
@ -1,27 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#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,10 +4,7 @@
|
|||||||
#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
|
||||||
@ -55,4 +52,9 @@ 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,10 +19,7 @@ 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);
|
||||||
|
|
||||||
// Returns a string representation of the Token.
|
void token_print(Token* token);
|
||||||
char* token_to_str(Token* token, unsigned int indent);
|
static char* token_type_str(Token* token);
|
||||||
|
|
||||||
// Returns a string representation of the TokenType.
|
|
||||||
char* token_type_to_str(TokenType t);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
#ifdef DBG
|
int is_even(int n);
|
||||||
#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,5 +1,9 @@
|
|||||||
#include "include/lexer.h"
|
#include "include/lexer.h"
|
||||||
#include "include/util.h"
|
#include "include/token.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));
|
||||||
@ -8,7 +12,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;
|
||||||
|
|
||||||
@ -18,7 +22,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; i++) token_destroy(lexer->tokens[i]);
|
for (int i = 0; i < lexer->ntokens; token_destroy(lexer->tokens[i++]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_lex(Lexer* lexer) {
|
void lexer_lex(Lexer* lexer) {
|
||||||
@ -33,13 +37,11 @@ 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;
|
||||||
|
|
||||||
@ -57,7 +59,6 @@ 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;
|
||||||
|
|
||||||
@ -70,8 +71,6 @@ 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) {
|
||||||
@ -82,8 +81,29 @@ 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] = token;
|
lexer->tokens[lexer->ntokens - 1] = 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,17 +1,14 @@
|
|||||||
#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 = "aa11";
|
text = "a1b2";
|
||||||
|
|
||||||
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,5 +1,4 @@
|
|||||||
#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));
|
||||||
@ -15,8 +14,17 @@ void token_destroy(Token* t) {
|
|||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* token_to_str(Token* token, unsigned int indent) {
|
void token_print(Token* token) {
|
||||||
char* title = malloc(sizeof("Token @ 0x000000000000\n"));
|
printf("Token @%p:\n", token);
|
||||||
sprintf(title, "Token @%p\n", token);
|
printf("\ttype: %s\n", token_type_str(token));
|
||||||
return title;
|
printf("\tval: %s\n", token->val);
|
||||||
|
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 +1,3 @@
|
|||||||
#include "include/util.h"
|
#include "include/util.h"
|
||||||
|
|
||||||
|
int is_even(int n) { return !(n % 2); }
|
||||||
|
37
test/dstr.c
37
test/dstr.c
@ -1,37 +0,0 @@
|
|||||||
#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
52
test/lexer.c
@ -1,52 +0,0 @@
|
|||||||
#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
Normal file
18
test/util.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#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