Compare commits
No commits in common. "d244cfbfe10095fb7d289817c9f87e46e255fb65" and "aae84024034c65b5a37183a4240be148c2d350cd" have entirely different histories.
d244cfbfe1
...
aae8402403
15
README.md
15
README.md
@ -1,3 +1,16 @@
|
|||||||
# SCL: Simple Calculator Language
|
# SCL: Simple Calculator Language
|
||||||
|
|
||||||
A rewrite of halk.
|
Project structure:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ tree -d
|
||||||
|
.
|
||||||
|
├── build # Build directory; where binaries (except the main one) go.
|
||||||
|
│ ├── obj # Project objects.
|
||||||
|
│ └── test # Test build directory.
|
||||||
|
│ └── obj # Test objects.
|
||||||
|
├── src # Source files (*.c).
|
||||||
|
│ └── include # Header files (*.h)
|
||||||
|
└── test # Tests (file names match those in src/*.c).
|
||||||
|
└── unity # Unity test framework files.
|
||||||
|
```
|
||||||
|
@ -8,20 +8,20 @@
|
|||||||
|
|
||||||
// What the lexer is currently looking at.
|
// What the lexer is currently looking at.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LEXER_STATE_CONFUSED, // Can't decide what it's looking at (also initial
|
LEXER_STATE_CONFUSED, // Can't decide what it's looking at (also initial
|
||||||
// state).
|
// state).
|
||||||
LEXER_STATE_NUM, // Looking at a number.
|
LEXER_STATE_NUM, // Looking at a number.
|
||||||
LEXER_STATE_CALL, // Looking at a call.
|
LEXER_STATE_CALL, // Looking at a call.
|
||||||
} LexerState;
|
} LexerState;
|
||||||
|
|
||||||
// Lexer: converts text to tokens.
|
// Lexer: converts text to tokens.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* src; // The source text.
|
char* src; // The source text.
|
||||||
size_t srcl; // The number of source chars.
|
size_t srcl; // The number of source chars.
|
||||||
char* cchar; // The current character.
|
char* cchar; // The current character.
|
||||||
Token** tokens; // The tokens produced.
|
Token** tokens; // The tokens produced.
|
||||||
size_t ntokens; // The number of tokens.
|
size_t ntokens; // The number of tokens.
|
||||||
LexerState state; // What the lexer is looking at.
|
LexerState state; // What the lexxer is looking at.
|
||||||
} Lexer;
|
} Lexer;
|
||||||
|
|
||||||
// Create a lexer.
|
// Create a lexer.
|
||||||
@ -42,7 +42,4 @@ void lexer_do_call(Lexer* lexer);
|
|||||||
// Convert text to tokens.
|
// Convert text to tokens.
|
||||||
void lexer_lex(Lexer* lexer);
|
void lexer_lex(Lexer* lexer);
|
||||||
|
|
||||||
// Add a token to the lexer.
|
|
||||||
void lexer_add_token(Lexer* lexer, Token* token);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,4 +10,21 @@
|
|||||||
// - Expression 1
|
// - Expression 1
|
||||||
// - Expression 2
|
// - Expression 2
|
||||||
|
|
||||||
|
typedef enum OpType {
|
||||||
|
OPTYPE_PLUS,
|
||||||
|
OPTYPE_MINUS
|
||||||
|
} optype_t;
|
||||||
|
|
||||||
|
typedef union Exp {
|
||||||
|
typedef struct Op {
|
||||||
|
optype_t type;
|
||||||
|
Exp* exp1;
|
||||||
|
Exp* exp2;
|
||||||
|
} op_t;
|
||||||
|
|
||||||
|
int n;
|
||||||
|
} exp_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,7 +9,7 @@ typedef enum {
|
|||||||
// Token.
|
// Token.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TokenType type; // The type of the Token.
|
TokenType type; // The type of the Token.
|
||||||
char* val; // The text of the Token.
|
char* val; // The text of the Token.
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
Token* token_init(TokenType type, char* val);
|
Token* token_init(TokenType type, char* val);
|
||||||
|
12
src/include/util.c
Normal file
12
src/include/util.c
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
// Utilies.
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// Exit with an error. Returns int for ease of use, but should be treated as void.
|
||||||
|
int die(char* msg);
|
||||||
|
|
||||||
|
#endif
|
17
src/lexer.c
17
src/lexer.c
@ -1,6 +1,4 @@
|
|||||||
#include "include/lexer.h"
|
#include "include/lexer.h"
|
||||||
#include "include/token.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
Lexer* lexer_init(char* src) {
|
Lexer* lexer_init(char* src) {
|
||||||
Lexer* lexer = malloc(sizeof(Lexer));
|
Lexer* lexer = malloc(sizeof(Lexer));
|
||||||
@ -22,15 +20,7 @@ void lexer_destroy(Lexer* lexer) {
|
|||||||
for (int i = 0; i < lexer->ntokens; token_destroy(lexer->tokens[i++]));
|
for (int i = 0; i < lexer->ntokens; token_destroy(lexer->tokens[i++]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_do_confused(Lexer* lexer) {
|
void lexer_do_confused(Lexer* lexer) {}
|
||||||
int c = atoi(lexer->cchar);
|
|
||||||
|
|
||||||
if (c) lexer_add_token(lexer, token_init(TOKEN_TYPE_NUMBER, lexer->cchar));
|
|
||||||
else lexer_add_token(lexer, token_init(TOKEN_TYPE_CALL, lexer->cchar));
|
|
||||||
}
|
|
||||||
|
|
||||||
void lexer_do_number(Lexer* lexer) {}
|
|
||||||
void lexer_do_call(Lexer* lexer) {}
|
|
||||||
|
|
||||||
void lexer_lex(Lexer* lexer) {
|
void lexer_lex(Lexer* lexer) {
|
||||||
while (*lexer->cchar) {
|
while (*lexer->cchar) {
|
||||||
@ -42,8 +32,3 @@ void lexer_lex(Lexer* lexer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_add_token(Lexer* lexer, Token* token) {
|
|
||||||
(void)reallocarray(lexer->tokens, lexer->ntokens++, sizeof(Token));
|
|
||||||
lexer->tokens[lexer->ntokens-1] = token;
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
#include "include/util.h"
|
#include "include/util.h"
|
||||||
|
|
||||||
int is_even(int n) { return !(n % 2); }
|
int is_even(int n) {
|
||||||
|
return !(n%2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "registry.h"
|
|
||||||
#include "unity/unity.h"
|
#include "unity/unity.h"
|
||||||
|
#include "registry.h"
|
||||||
|
|
||||||
void (*tests[30])();
|
void (*tests[30])();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "registry.h"
|
|
||||||
#include "unity/unity_internals.h"
|
#include "unity/unity_internals.h"
|
||||||
|
#include "registry.h"
|
||||||
|
|
||||||
#define TESTS_MAX 128
|
#define TESTS_MAX 128
|
||||||
|
|
||||||
@ -7,14 +7,13 @@ static Test tests[TESTS_MAX];
|
|||||||
static int test_count = 0;
|
static int test_count = 0;
|
||||||
|
|
||||||
void register_test(Test t) {
|
void register_test(Test t) {
|
||||||
if (test_count < TESTS_MAX) {
|
if (test_count < TESTS_MAX) {
|
||||||
tests[test_count] = t;
|
tests[test_count] = t;
|
||||||
test_count++;
|
test_count++;
|
||||||
} else printf("Maximum number of tests (%d) exceeded.\n", TESTS_MAX);
|
} else
|
||||||
|
printf("Maximum number of tests (%d) exceeded.\n", TESTS_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_all_tests() {
|
void run_all_tests() {
|
||||||
for (int i = 0; i < test_count; i++) {
|
for (int i = 0; i < test_count; i++) tests[i]();
|
||||||
int res = tests[i]();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
#define REGISTRY_H
|
#define REGISTRY_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "unity/unity.h"
|
|
||||||
|
|
||||||
typedef int (*Test)(void);
|
// Test functions neither consume nor return anything.
|
||||||
|
typedef void (*Test)(void);
|
||||||
|
|
||||||
// Register a new test function.
|
// Register a new test function.
|
||||||
void register_test(Test);
|
void register_test(Test t);
|
||||||
|
|
||||||
// Run all registered tests.
|
// Run all registered tests.
|
||||||
void run_all_tests();
|
void run_all_tests();
|
||||||
|
24
test/token.c
24
test/token.c
@ -1,19 +1,31 @@
|
|||||||
#include "unity/unity.h"
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "unity/unity.h"
|
||||||
|
|
||||||
#include "../src/include/token.h"
|
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
|
#include "unity/unity_internals.h"
|
||||||
|
#include "../src/include/token.h"
|
||||||
|
|
||||||
int test_token_init() {
|
void test_token_init() {
|
||||||
UNITY_BEGIN();
|
|
||||||
char* s = malloc(sizeof("Hello, world!"));
|
char* s = malloc(sizeof("Hello, world!"));
|
||||||
s = "Hello, world!";
|
s = "Hello, world!";
|
||||||
Token* t = token_init(TOKEN_TYPE_CALL, s);
|
Token* t = token_init(TOKEN_TYPE_CALL, s);
|
||||||
TEST_ASSERT_EQUAL(TOKEN_TYPE_CALL, t->type);
|
TEST_ASSERT_EQUAL(TOKEN_TYPE_CALL, t->type);
|
||||||
TEST_ASSERT_EQUAL_STRING("Hello, world!", t->val);
|
TEST_ASSERT_EQUAL_STRING("Hello, world!", t->val);
|
||||||
return UNITY_END();
|
}
|
||||||
|
|
||||||
|
void test_token_destroy() {
|
||||||
|
char* s = malloc(1 * sizeof(char));
|
||||||
|
*s = 'h';
|
||||||
|
Token* t = token_init(TOKEN_TYPE_CALL, s);
|
||||||
|
token_destroy(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void token_test() {
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(test_token_init);
|
||||||
|
UNITY_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((constructor)) void register_tests_token() {
|
__attribute__((constructor)) void register_tests_token() {
|
||||||
register_test(test_token_init);
|
register_test(token_test);
|
||||||
}
|
}
|
||||||
|
17
test/util.c
17
test/util.c
@ -1,14 +1,19 @@
|
|||||||
#include "../src/include/util.h"
|
|
||||||
#include "registry.h"
|
|
||||||
#include "unity/unity.h"
|
#include "unity/unity.h"
|
||||||
|
#include "registry.h"
|
||||||
|
#include "unity/unity_internals.h"
|
||||||
|
#include "../src/include/util.h"
|
||||||
|
|
||||||
int test_is_even() {
|
void test_is_even() {
|
||||||
UNITY_BEGIN();
|
|
||||||
TEST_ASSERT_EQUAL(0, is_even(1));
|
TEST_ASSERT_EQUAL(0, is_even(1));
|
||||||
TEST_ASSERT_EQUAL(1, is_even(2));
|
TEST_ASSERT_EQUAL(1, is_even(2));
|
||||||
return UNITY_END();
|
}
|
||||||
|
|
||||||
|
void util_test() {
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(test_is_even);
|
||||||
|
UNITY_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((constructor)) void register_tests_util() {
|
__attribute__((constructor)) void register_tests_util() {
|
||||||
register_test(test_is_even);
|
register_test(util_test);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user