Compare commits

..

No commits in common. "905acacd07770c69c8b1aa975d5a83540fc62219" and "4514d94be91a77bd5f422acd535c05931a665090" have entirely different histories.

17 changed files with 192 additions and 186 deletions

View File

@ -1,13 +1,12 @@
--- ---
BasedOnStyle: LLVM
AlignConsecutiveShortCaseStatements: AlignConsecutiveShortCaseStatements:
Enabled: true Enabled: true
AcrossEmptyLines: true AcrossEmptyLines: true
AcrossComments: true AcrossComments: true
IndentCaseLabels: true
AllowShortBlocksOnASingleLine: Always AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: true AllowShortCaseLabelsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: AllIfsAndElse AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLoopsOnASingleLine: true AllowShortLoopsOnASingleLine: true
IndentWidth: 4 IndentWidth: 4
PointerAlignment: Left PointerAlignment: Left
AlignAfterOpenBracket: BlockIndent

1
.gitignore vendored
View File

@ -5,4 +5,3 @@ tags
.cache .cache
build/* build/*
compile_commands.json compile_commands.json
vgcore.*

View File

@ -14,7 +14,7 @@ TEST_OBJ_DIR = $(TEST_BUILD_DIR)/obj
CC = clang CC = clang
LINK = clang LINK = clang
CFLAGS = -Wall -DDBG -ggdb CFLAGS = -Wall -DDBG -ggdb
LDFLAGS = -lm LDFLAGS =
SRC_FILES = $(wildcard $(SRC_DIR)/*.c) SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
OBJ_FILES = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC_FILES)) OBJ_FILES = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC_FILES))

View File

@ -1,4 +1,4 @@
# SCL: Simple CAS Language # SCL: Simple Calculator Language
## Syntax ## Syntax
@ -12,24 +12,16 @@ As one would expect, you can evaluate simple infix expressions:
You can also define your own functions: You can also define your own functions:
```scl ```scl
> f(x) = 2x > f(x) 2x
> f(2) > f(2)
= 4 = 4
``` ```
Symbolic algebra is done in the following manner:
```scl
> f(x) = e^x
> diff(f, x:sym, 2)
= e^x
```
SCL will dynamically decide on types, but you can state them explicitly as SCL will dynamically decide on types, but you can state them explicitly as
well: well:
```scl ```scl
> f(x:int) = 2x > f(x:int) 2x
> f(2.2) > f(2.2)
! f(x:int): x must be of type int. ! f(x:int): x must be of type int.
``` ```
@ -40,5 +32,6 @@ Variables can be defined, with several attributes:
> a = 1 // Interpret type automatically. > a = 1 // Interpret type automatically.
> b:int = 1 // Must be int. > b:int = 1 // Must be int.
> c:const:int = 1 // Constant: value can never change. > c:const:int = 1 // Constant: value can never change.
> x:sym // Treated symbolicaly. > d:lazy = (1 + 1) // Interpreter will wait as long as possible before
// evaluating.
``` ```

View File

@ -1,7 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include "include/ast.h" #include "include/ast.h"
#include "include/dstr.h"
#include "include/util.h" #include "include/util.h"
extern AST* root; extern AST* root;
@ -24,59 +23,36 @@ void ast_destroy(AST* ast) {
if (!ast) return; if (!ast) return;
switch (ast->type) { switch (ast->type) {
case AST_TYPE_NUM: ast_num_data_destroy(ast->data); break; case AST_TYPE_NUM: ast_type_num_destroy(ast->data); break;
case AST_TYPE_CALL: ast_call_data_destroy(ast->data); break; case AST_TYPE_CALL: ast_type_call_destroy(ast->data); break;
default: default: log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX);
log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX);
} }
} }
void ast_print(AST* ast) { ast_print_i(ast, 0); } void ast_print(AST* ast) {
log_dbgf("Tree type: %s", asttype_names[ast->type]);
void ast_print_i(AST* ast, int i) { fflush(stdout);
INDENT_BEGIN(i);
INDENT_TITLE("AST", ast);
INDENT_FIELD("type", "%s", asttype_names[ast->type]);
INDENT_FIELD_EXT_NONL_START("data");
switch (ast->type) {
case AST_TYPE_NUM:
printf("%s %lf\n", INDENT_spacing->buf, *(ASTNumData*)ast->data);
break;
case AST_TYPE_CALL: ast_call_print(ast->data, i + 2); break;
default: exit(1);
}
INDENT_FIELD_NONL_END;
INDENT_END;
} }
ASTNumData* ast_num_data_init(double val) {
ASTNumData* ast_type_num_init(int val) {
talloc(ASTNumData, num); talloc(ASTNumData, num);
log_dbgf("val: %lf", val); num->val = val;
*num = val;
return num; return num;
} }
void ast_num_data_destroy(ASTNumData* num) { void ast_type_num_destroy(ASTNumData* num) {
if (!num) return free(num); if (!num)
return
free(num);
} }
void ast_num_print(ASTNumData* data, int i) { ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv) {
INDENT_BEGIN(i);
INDENT_FIELD("data", "%lf", *data);
INDENT_END;
}
ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv) {
talloc(ASTCallData, call); talloc(ASTCallData, call);
log_dbgf("to: %s", to);
call->to = to; call->to = to;
call->argc = argc; call->argc = argc;
call->argv = argv; call->argv = argv;
@ -84,19 +60,11 @@ ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv) {
return call; return call;
} }
void ast_call_data_destroy(ASTCallData* call) { void ast_type_call_destroy(ASTCallData* call) {
if (!call) return free(call->to); if (!call)
return
free(call->to);
for (size_t i = 0; i < call->argc; i++) free(call->argv[i]); for (size_t i = 0; i < call->argc; i++) free(call->argv[i]);
free(call); free(call);
} }
void ast_call_print(ASTCallData* data, int i) {
INDENT_BEGIN(i);
INDENT_TITLE("ASTCallData", data);
INDENT_FIELD("to", "%s", data->to);
INDENT_FIELD("argc", "%ld", data->argc);
INDENT_FIELD_LIST("argv", data->argv, data->argc, ast_print_i);
INDENT_END;
}

View File

@ -25,10 +25,8 @@ void dstr_append(Dstr* dest, char* src, size_t ln) {
// Double the buffer size when overflown. // Double the buffer size when overflown.
dest->bufsz *= 2; dest->bufsz *= 2;
dest->buf = realloc(dest->buf, dest->bufsz); dest->buf = realloc(dest->buf, dest->bufsz);
log_dbgf( log_dbgf("dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
"dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2, dest->bufsz);
dest->bufsz
);
} }
// Overwrites the \0 at the end of the string, keeps the null from the given // Overwrites the \0 at the end of the string, keeps the null from the given
@ -42,10 +40,8 @@ void dstr_appendch(Dstr* dest, char ch) {
// Double the buffer size when overflown. // Double the buffer size when overflown.
dest->bufsz *= 2; dest->bufsz *= 2;
dest->buf = realloc(dest->buf, dest->bufsz); dest->buf = realloc(dest->buf, dest->bufsz);
log_dbgf( log_dbgf("dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
"dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2, dest->bufsz);
dest->bufsz
);
} }
// Overwrites the preexisting null terminator, and adds one of its own. // Overwrites the preexisting null terminator, and adds one of its own.

View File

@ -7,33 +7,26 @@
extern AST* root; extern AST* root;
ASTNumData exec_expr(AST* ast) { void exec_expr() {
// ast_print(ast); ast_print(root);
log_dbg("Started execution."); log_dbg("Started execution.");
switch (ast->type) { switch (root->type) {
case AST_TYPE_CALL: return exec_call(ast); case AST_TYPE_CALL: exec_call(); break;
case AST_TYPE_NUM: return *(ASTNumData*)ast->data;
default: printf("what\n"); default: printf("what\n");
} }
} }
ASTNumData exec_call(AST* ast) { void exec_call() {
log_dbg("Started call execution."); log_dbg("Started call execution.");
fflush(stdout); fflush(stdout);
ASTCallData* calldata = (ASTCallData*)ast->data; ASTCallData* calldata = (ASTCallData*)root->data;
if (!strcmp(calldata->to, "+") && calldata->argc == 2) { if (!strcmp(calldata->to, "+") && calldata->argc == 2) {
/*
ASTNumData* n1 = (ASTNumData*)calldata->argv[0]->data; ASTNumData* n1 = (ASTNumData*)calldata->argv[0]->data;
ASTNumData* n2 = (ASTNumData*)calldata->argv[1]->data; ASTNumData* n2 = (ASTNumData*)calldata->argv[1]->data;
*/
ASTNumData n1 = exec_expr(calldata->argv[0]); exec_return(n1->val + n2->val);
ASTNumData n2 = exec_expr(calldata->argv[1]);
return n1 + n2;
} }
return -1000;
} }
void exec_print(double n) { printf("= %lf\n", n); } void exec_return(int n) { printf("= %d\n", n); }

View File

@ -14,14 +14,14 @@
} }
%union { %union {
double fval; int intval;
char* strval; char* strval;
AST* ast; AST* ast;
} }
%define parse.error verbose %define parse.error verbose
%token<fval> NUM %token<intval> NUM
%token<strval> CALL %token<strval> CALL
%token PLUS %token PLUS
%token NL %token NL
@ -35,12 +35,13 @@ input:
; ;
exp: exp:
NUM { $$ = ast_init(AST_TYPE_NUM, ast_num_data_init($1)); } NUM { $$ = ast_init(AST_TYPE_NUM, ast_type_num_init($1)); }
| NUM PLUS NUM { | NUM PLUS NUM {
AST** argv = calloc(2, sizeof(AST*)); AST* argv[2] = {
argv[0] = ast_init(AST_TYPE_NUM, ast_num_data_init($1)); ast_init(AST_TYPE_NUM, ast_type_num_init($1)),
argv[1] = ast_init(AST_TYPE_NUM, ast_num_data_init($3)); ast_init(AST_TYPE_NUM, ast_type_num_init($3))
$$ = ast_init(AST_TYPE_CALL, ast_call_data_init("+", 2, argv)); };
} $$ = ast_init(AST_TYPE_CALL, ast_type_call_init("+", 2, argv));
};
%% %%

View File

@ -17,13 +17,13 @@ typedef struct {
AST* ast_init(ASTType type, void* data); AST* ast_init(ASTType type, void* data);
void ast_destroy(AST* ast); void ast_destroy(AST* ast);
void ast_print(AST* ast); void ast_print(AST* ast);
void ast_print_i(AST* ast, int i);
typedef double ASTNumData; typedef struct {
int val;
} ASTNumData;
ASTNumData* ast_num_data_init(double val); ASTNumData* ast_type_num_init(int val);
void ast_num_data_destroy(ASTNumData* num); void ast_type_num_destroy(ASTNumData* num);
void ast_num_print(ASTNumData*, int i);
typedef struct { typedef struct {
char* to; // What the call's to. char* to; // What the call's to.
@ -31,8 +31,7 @@ typedef struct {
AST** argv; // Argument vector. AST** argv; // Argument vector.
} ASTCallData; } ASTCallData;
ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv); ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv);
void ast_call_data_destroy(ASTCallData* call); void ast_type_call_destroy(ASTCallData* call);
void ast_call_print(ASTCallData*, int i);
#endif #endif

View File

@ -1,10 +1,8 @@
#ifndef EXEC_H #ifndef EXEC_H
#define EXEC_H #define EXEC_H
#include "ast.h" void exec_expr();
void exec_call();
ASTNumData exec_expr(AST* ast); void exec_return(int n);
ASTNumData exec_call(AST* ast);
void exec_print(double n);
#endif #endif

View File

@ -4,25 +4,19 @@
#include <assert.h> #include <assert.h>
#ifdef __has_include #ifdef __has_include
#if __has_include("../../build/grammars/grammar.tab.h") #if __has_include("../../build/grammars/grammar.tab.h")
#include "../../build/grammars/grammar.tab.h" #include "../../build/grammars/grammar.tab.h"
#else
#warn "Build resources not present!"
#endif
#else #else
#warn "Build resources not present!" #warn "Not sure whether build-time resources are present."
#endif #include "../../build/grammars/grammar.tab.h"
#else
#warn "Not sure whether build-time resources are present."
#include "../../build/grammars/grammar.tab.h"
#endif #endif
extern YYSTYPE yylval; extern YYSTYPE yylval;
extern char* inp; extern char* inp;
// Accumulate an integer.
int acc_int(int c);
// Accumulate a floating-point number.
double acc_float(int c);
// Called by `yyparse()` (in bison-generated files.) // Called by `yyparse()` (in bison-generated files.)
int yylex(); int yylex();
void yyerror(char const* s); void yyerror(char const* s);

39
src/include/token.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef TOKEN_H
#define TOKEN_H
#include <stdlib.h>
typedef enum {
TOKEN_TYPE_CALL,
TOKEN_TYPE_NUMBER,
TOKEN_TYPE_MAX = TOKEN_TYPE_NUMBER,
} TokenType;
// Token.
typedef struct {
TokenType type; // The type of the Token.
size_t valn; // The length of val.
char* val; // The text of the Token.
size_t len; // Length of the text of the Token.
} Token;
Token* token_init(TokenType type, char* val, size_t valn);
void token_destroy(Token* token);
// Prints out a representation of the Token.
void token_print(Token* token);
// Prints out a representation of the Token, with the specified indent level.
void token_print_i(Token* token, int ilevel);
// Prints out a representation of the TokenType.
void tokentype_print(TokenType t);
// Prints out a representation of the TokenType, with the specified indent
// level.
void tokentype_print_i(TokenType t, int ilevel);
// Prints a token's type. That's it.
void tokentype_print_raw(TokenType t);
#endif

View File

@ -50,7 +50,7 @@
// Print & indent the title of a section. // Print & indent the title of a section.
#define INDENT_TITLE(THING, WHERE) \ #define INDENT_TITLE(THING, WHERE) \
printf("%s" COL_BCYA THING COL_RESET " @" COL_MAG " %p\n" COL_RESET, INDENT_spacing->buf, WHERE); printf("%s" COL_BCYA THING " @ %p\n" COL_RESET, INDENT_spacing->buf, WHERE);
// Print & indent a thing. // Print & indent a thing.
#define INDENT_FIELD(FIELD, VAL, ...) \ #define INDENT_FIELD(FIELD, VAL, ...) \
@ -64,8 +64,8 @@
INDENT_spacing->buf, INDENT_spacing->buf, __VA_ARGS__); INDENT_spacing->buf, INDENT_spacing->buf, __VA_ARGS__);
// Print & indent a thing without any newline. // Print & indent a thing without any newline.
#define INDENT_FIELD_EXT_NONL_START(FIELD) \ #define INDENT_FIELD_NONL_START(FIELD) \
printf("%s " COL_BWHI FIELD ":\n" COL_RESET COL_WHI, INDENT_spacing->buf); printf("%s " COL_BWHI FIELD ": " COL_RESET COL_WHI, INDENT_spacing->buf);
#define INDENT_FIELD_NONL_END printf( "\n" COL_RESET); #define INDENT_FIELD_NONL_END printf( "\n" COL_RESET);
// Print an array A of N things, by calling the function F. // Print an array A of N things, by calling the function F.

View File

@ -1,52 +1,9 @@
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include "include/lexer.h" #include "include/lexer.h"
int acc_int(int c) {
int value = c - '0';
while (isdigit(*inp)) {
value = value * 10 + (*inp - '0'); // Accumulate value.
inp++;
}
return value;
}
double acc_float(int c) {
int dplaces = 0;
double value = (double)(c - '0');
// Grab everything prior to '.'.
while (isdigit(*inp)) {
value = value * 10 + (*inp - '0'); // Accumulate value.
inp++;
}
if (*inp == '.') {
inp++;
while (isdigit(*inp)) {
// TODO:
// Accumulate as int, divide once at end.
// value = value + (((double)(*inp - '0'))/pow(10.0l,
// (double)(inp-oinp))); // Accumulate value.
value = value * 10 + (*inp - '0'); // Accumulate value.
dplaces++;
inp++;
}
value = value / pow(10, dplaces);
}
// > 1.20000
// = 1.0 + 2/10
// > 1.23
// = 1.2 + 3/100
return value;
}
int yylex() { int yylex() {
if (*inp == '\0') return YYEOF; if (*inp == '\0') return YYEOF;
@ -58,7 +15,12 @@ int yylex() {
// Check for NUM. // Check for NUM.
if (isdigit(c)) { if (isdigit(c)) {
yylval.fval = acc_float(c); // Set the token value. int value = c - '0';
while (isdigit(*inp)) {
value = value * 10 + (*inp - '0'); // Accumulate value.
inp++;
}
yylval.intval = value; // Set the token value.
return NUM; return NUM;
} }
@ -72,4 +34,4 @@ int yylex() {
return 0; return 0;
} }
void yyerror(char const* s) { fprintf(stderr, "Parse error: %s\n", s); } void yyerror(char const* s) { fprintf(stderr, "Syntax error:\n%s\n", s); }

View File

@ -2,9 +2,9 @@
#include "include/ast.h" #include "include/ast.h"
#include "include/dstr.h" #include "include/dstr.h"
#include "include/exec.h"
#include "include/lexer.h" #include "include/lexer.h"
#include "include/util.h" #include "include/util.h"
#include "include/exec.h"
#include "../build/grammars/grammar.tab.h" #include "../build/grammars/grammar.tab.h"
@ -31,6 +31,7 @@ int main(int argc, char** argv) {
switch (c) { switch (c) {
case EOF: dstr_destroy(ln); goto lnskip; case EOF: dstr_destroy(ln); goto lnskip;
case '\n': goto lnend; case '\n': goto lnend;
default: dstr_appendch(ln, c); log_dbgf("cchar: %c", c); default: dstr_appendch(ln, c); log_dbgf("cchar: %c", c);
} }
} while (1); } while (1);
@ -40,12 +41,14 @@ int main(int argc, char** argv) {
log_dbgf("cline: %s", ln->buf); log_dbgf("cline: %s", ln->buf);
if (ln->ln > 0) { if (ln->ln > 0) {
// I hope it's null-terminated.
inp = ln->buf; inp = ln->buf;
if (yyparse() == 0) printf("Parsed successfully!\n"); if (yyparse() == 0)
else printf("Parse error.\n"); printf("Parsed successfully!\n");
else
printf("Parse error.\n");
exec_print(exec_expr(root)); exec_expr();
ast_print(root);
} }
dstr_destroy(ln); dstr_destroy(ln);

View File

@ -2,8 +2,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "include/stack.h"
#include "include/util.h" #include "include/util.h"
#include "include/stack.h"
Stack* stack_init() { Stack* stack_init() {
talloc(Stack, stack); talloc(Stack, stack);

62
src/token.c Normal file
View File

@ -0,0 +1,62 @@
#include <stdio.h>
#include "include/token.h"
#include "include/dstr.h"
#include "include/util.h"
static char* tokentype_names[] = {
[TOKEN_TYPE_CALL] = "CALL",
[TOKEN_TYPE_NUMBER] = "NUMBER",
};
Token* token_init(TokenType type, char* val, size_t valn) {
Token* t = malloc(sizeof(Token));
t->type = type;
t->valn = valn;
t->val = val;
return t;
}
void token_destroy(Token* t) {
free(t->val);
free(t);
}
void token_print(Token* token) { token_print_i(token, 0); }
void token_print_i(Token *token, int ilvl) {
INDENT_BEGIN(ilvl);
INDENT_TITLE("Token", token);
INDENT_FIELD_NONL_START("type")
tokentype_print_raw(token->type);
INDENT_FIELD_NONL_END
INDENT_FIELD("valn", "%ld", token->valn);
INDENT_FIELD_NL("val", "\"%s\"", token->val);
}
void tokentype_print_raw(TokenType t) {
if (t > TOKEN_TYPE_MAX) {
printf("Unknown (%d)", t);
log_dbgf("%d is not a valid TokenType (max: %d)", t, TOKEN_TYPE_MAX);
return;
}
printf("%s", tokentype_names[t]);
}
void tokentype_print(TokenType t) { tokentype_print_i(t, 0); }
void tokentype_print_i(TokenType t, int i) {
INDENT_BEGIN(i);
if (t > TOKEN_TYPE_MAX) {
INDENT_FIELD("val", "Unknown (%d)", t);
log_dbgf("%d is not a valid TokenType (max: %d)", t, TOKEN_TYPE_MAX);
return;
}
INDENT_FIELD("val", "%s", tokentype_names[t]);
}