Compare commits

...

9 Commits

Author SHA1 Message Date
905acacd07 Fixed float addition.
One can now add floats, will also print the AST.
2024-12-21 10:12:30 -05:00
8763fa35dd Updated README.md 2024-12-14 20:35:36 -05:00
feae5d560a Trimmed grammars. 2024-12-07 11:02:22 -05:00
ec268f6047 Nothing works. 2024-12-07 11:01:00 -05:00
6fff5e5cc8 Without token.c. 2024-12-07 10:33:30 -05:00
7b19e553f2 With token.c. 2024-12-07 10:33:16 -05:00
64ef797727 Things. 2024-12-07 09:16:17 -05:00
85e17ede84 Addition with floats is now entirely possible. 2024-11-30 11:15:18 -05:00
8e5b39a6e4 Can now do integer addition (with floats! :D). 2024-11-30 10:44:21 -05:00
17 changed files with 186 additions and 192 deletions

View File

@ -1,12 +1,13 @@
--- ---
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,3 +5,4 @@ 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 = LDFLAGS = -lm
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 Calculator Language # SCL: Simple CAS Language
## Syntax ## Syntax
@ -12,16 +12,24 @@ 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.
``` ```
@ -32,6 +40,5 @@ 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.
> d:lazy = (1 + 1) // Interpreter will wait as long as possible before > x:sym // Treated symbolicaly.
// evaluating.
``` ```

View File

@ -1,6 +1,7 @@
#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;
@ -23,36 +24,59 @@ void ast_destroy(AST* ast) {
if (!ast) return; if (!ast) return;
switch (ast->type) { switch (ast->type) {
case AST_TYPE_NUM: ast_type_num_destroy(ast->data); break; case AST_TYPE_NUM: ast_num_data_destroy(ast->data); break;
case AST_TYPE_CALL: ast_type_call_destroy(ast->data); break; case AST_TYPE_CALL: ast_call_data_destroy(ast->data); break;
default: log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX); default:
log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX);
} }
} }
void ast_print(AST* ast) { void ast_print(AST* ast) { ast_print_i(ast, 0); }
log_dbgf("Tree type: %s", asttype_names[ast->type]);
fflush(stdout); void ast_print_i(AST* ast, int i) {
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);
num->val = val; log_dbgf("val: %lf", val);
*num = val;
return num; return num;
} }
void ast_type_num_destroy(ASTNumData* num) { void ast_num_data_destroy(ASTNumData* num) {
if (!num) if (!num) return free(num);
return
free(num);
} }
ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv) { void ast_num_print(ASTNumData* data, int i) {
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;
@ -60,11 +84,19 @@ ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv) {
return call; return call;
} }
void ast_type_call_destroy(ASTCallData* call) { void ast_call_data_destroy(ASTCallData* call) {
if (!call) if (!call) return free(call->to);
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,8 +25,10 @@ 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("dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2, log_dbgf(
dest->bufsz); "dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
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
@ -40,8 +42,10 @@ 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("dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2, log_dbgf(
dest->bufsz); "dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
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,26 +7,33 @@
extern AST* root; extern AST* root;
void exec_expr() { ASTNumData exec_expr(AST* ast) {
ast_print(root); // ast_print(ast);
log_dbg("Started execution."); log_dbg("Started execution.");
switch (root->type) { switch (ast->type) {
case AST_TYPE_CALL: exec_call(); break; case AST_TYPE_CALL: return exec_call(ast);
case AST_TYPE_NUM: return *(ASTNumData*)ast->data;
default: printf("what\n"); default: printf("what\n");
} }
} }
void exec_call() { ASTNumData exec_call(AST* ast) {
log_dbg("Started call execution."); log_dbg("Started call execution.");
fflush(stdout); fflush(stdout);
ASTCallData* calldata = (ASTCallData*)root->data; ASTCallData* calldata = (ASTCallData*)ast->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;
*/
exec_return(n1->val + n2->val); ASTNumData n1 = exec_expr(calldata->argv[0]);
ASTNumData n2 = exec_expr(calldata->argv[1]);
return n1 + n2;
} }
return -1000;
} }
void exec_return(int n) { printf("= %d\n", n); } void exec_print(double n) { printf("= %lf\n", n); }

View File

@ -14,14 +14,14 @@
} }
%union { %union {
int intval; double fval;
char* strval; char* strval;
AST* ast; AST* ast;
} }
%define parse.error verbose %define parse.error verbose
%token<intval> NUM %token<fval> NUM
%token<strval> CALL %token<strval> CALL
%token PLUS %token PLUS
%token NL %token NL
@ -35,13 +35,12 @@ input:
; ;
exp: exp:
NUM { $$ = ast_init(AST_TYPE_NUM, ast_type_num_init($1)); } NUM { $$ = ast_init(AST_TYPE_NUM, ast_num_data_init($1)); }
| NUM PLUS NUM { | NUM PLUS NUM {
AST* argv[2] = { AST** argv = calloc(2, sizeof(AST*));
ast_init(AST_TYPE_NUM, ast_type_num_init($1)), argv[0] = ast_init(AST_TYPE_NUM, ast_num_data_init($1));
ast_init(AST_TYPE_NUM, ast_type_num_init($3)) argv[1] = ast_init(AST_TYPE_NUM, ast_num_data_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 struct { typedef double ASTNumData;
int val;
} ASTNumData;
ASTNumData* ast_type_num_init(int val); ASTNumData* ast_num_data_init(double val);
void ast_type_num_destroy(ASTNumData* num); void ast_num_data_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,7 +31,8 @@ typedef struct {
AST** argv; // Argument vector. AST** argv; // Argument vector.
} ASTCallData; } ASTCallData;
ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv); ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv);
void ast_type_call_destroy(ASTCallData* call); void ast_call_data_destroy(ASTCallData* call);
void ast_call_print(ASTCallData*, int i);
#endif #endif

View File

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

View File

@ -4,19 +4,25 @@
#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 "Not sure whether build-time resources are present." #warn "Build resources not present!"
#include "../../build/grammars/grammar.tab.h" #endif
#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);

View File

@ -1,39 +0,0 @@
#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 " @ %p\n" COL_RESET, INDENT_spacing->buf, WHERE); printf("%s" COL_BCYA THING COL_RESET " @" COL_MAG " %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_NONL_START(FIELD) \ #define INDENT_FIELD_EXT_NONL_START(FIELD) \
printf("%s " COL_BWHI FIELD ": " COL_RESET COL_WHI, INDENT_spacing->buf); printf("%s " COL_BWHI FIELD ":\n" 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,9 +1,52 @@
#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;
@ -15,12 +58,7 @@ int yylex() {
// Check for NUM. // Check for NUM.
if (isdigit(c)) { if (isdigit(c)) {
int value = c - '0'; yylval.fval = acc_float(c); // Set the token value.
while (isdigit(*inp)) {
value = value * 10 + (*inp - '0'); // Accumulate value.
inp++;
}
yylval.intval = value; // Set the token value.
return NUM; return NUM;
} }
@ -34,4 +72,4 @@ int yylex() {
return 0; return 0;
} }
void yyerror(char const* s) { fprintf(stderr, "Syntax error:\n%s\n", s); } void yyerror(char const* s) { fprintf(stderr, "Parse error: %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,7 +31,6 @@ 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);
@ -41,14 +40,12 @@ 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) if (yyparse() == 0) printf("Parsed successfully!\n");
printf("Parsed successfully!\n"); else printf("Parse error.\n");
else
printf("Parse error.\n");
exec_expr(); exec_print(exec_expr(root));
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/util.h"
#include "include/stack.h" #include "include/stack.h"
#include "include/util.h"
Stack* stack_init() { Stack* stack_init() {
talloc(Stack, stack); talloc(Stack, stack);

View File

@ -1,62 +0,0 @@
#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]);
}