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:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
IndentCaseLabels: true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLoopsOnASingleLine: true
IndentWidth: 4
PointerAlignment: Left
AlignAfterOpenBracket: BlockIndent

1
.gitignore vendored
View File

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

View File

@ -14,7 +14,7 @@ TEST_OBJ_DIR = $(TEST_BUILD_DIR)/obj
CC = clang
LINK = clang
CFLAGS = -Wall -DDBG -ggdb
LDFLAGS =
LDFLAGS = -lm
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
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
@ -12,16 +12,24 @@ As one would expect, you can evaluate simple infix expressions:
You can also define your own functions:
```scl
> f(x) 2x
> f(x) = 2x
> f(2)
= 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
well:
```scl
> f(x:int) 2x
> f(x:int) = 2x
> f(2.2)
! 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.
> b:int = 1 // Must be int.
> c:const:int = 1 // Constant: value can never change.
> d:lazy = (1 + 1) // Interpreter will wait as long as possible before
// evaluating.
> x:sym // Treated symbolicaly.
```

View File

@ -1,6 +1,7 @@
#include <stdio.h>
#include "include/ast.h"
#include "include/dstr.h"
#include "include/util.h"
extern AST* root;
@ -23,36 +24,59 @@ void ast_destroy(AST* ast) {
if (!ast) return;
switch (ast->type) {
case AST_TYPE_NUM: ast_type_num_destroy(ast->data); break;
case AST_TYPE_CALL: ast_type_call_destroy(ast->data); break;
default: log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX);
case AST_TYPE_NUM: ast_num_data_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);
}
}
void ast_print(AST* ast) {
log_dbgf("Tree type: %s", asttype_names[ast->type]);
fflush(stdout);
void ast_print(AST* ast) { ast_print_i(ast, 0); }
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_type_num_init(int val) {
ASTNumData* ast_num_data_init(double val) {
talloc(ASTNumData, num);
num->val = val;
log_dbgf("val: %lf", val);
*num = val;
return num;
}
void ast_type_num_destroy(ASTNumData* num) {
if (!num)
return
free(num);
void ast_num_data_destroy(ASTNumData* num) {
if (!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);
log_dbgf("to: %s", to);
call->to = to;
call->argc = argc;
call->argv = argv;
@ -60,11 +84,19 @@ ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv) {
return call;
}
void ast_type_call_destroy(ASTCallData* call) {
if (!call)
return
free(call->to);
void ast_call_data_destroy(ASTCallData* call) {
if (!call) return free(call->to);
for (size_t i = 0; i < call->argc; i++) free(call->argv[i]);
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.
dest->bufsz *= 2;
dest->buf = realloc(dest->buf, dest->bufsz);
log_dbgf("dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
dest->bufsz);
log_dbgf(
"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
@ -40,8 +42,10 @@ void dstr_appendch(Dstr* dest, char ch) {
// Double the buffer size when overflown.
dest->bufsz *= 2;
dest->buf = realloc(dest->buf, dest->bufsz);
log_dbgf("dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
dest->bufsz);
log_dbgf(
"dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
dest->bufsz
);
}
// Overwrites the preexisting null terminator, and adds one of its own.

View File

@ -7,26 +7,33 @@
extern AST* root;
void exec_expr() {
ast_print(root);
ASTNumData exec_expr(AST* ast) {
// ast_print(ast);
log_dbg("Started execution.");
switch (root->type) {
case AST_TYPE_CALL: exec_call(); break;
switch (ast->type) {
case AST_TYPE_CALL: return exec_call(ast);
case AST_TYPE_NUM: return *(ASTNumData*)ast->data;
default: printf("what\n");
}
}
void exec_call() {
ASTNumData exec_call(AST* ast) {
log_dbg("Started call execution.");
fflush(stdout);
ASTCallData* calldata = (ASTCallData*)root->data;
ASTCallData* calldata = (ASTCallData*)ast->data;
if (!strcmp(calldata->to, "+") && calldata->argc == 2) {
/*
ASTNumData* n1 = (ASTNumData*)calldata->argv[0]->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 {
int intval;
double fval;
char* strval;
AST* ast;
}
%define parse.error verbose
%token<intval> NUM
%token<fval> NUM
%token<strval> CALL
%token PLUS
%token NL
@ -35,13 +35,12 @@ input:
;
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 {
AST* argv[2] = {
ast_init(AST_TYPE_NUM, ast_type_num_init($1)),
ast_init(AST_TYPE_NUM, ast_type_num_init($3))
};
$$ = ast_init(AST_TYPE_CALL, ast_type_call_init("+", 2, argv));
};
AST** argv = calloc(2, sizeof(AST*));
argv[0] = ast_init(AST_TYPE_NUM, ast_num_data_init($1));
argv[1] = ast_init(AST_TYPE_NUM, ast_num_data_init($3));
$$ = ast_init(AST_TYPE_CALL, ast_call_data_init("+", 2, argv));
}
%%

View File

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

View File

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

View File

@ -17,6 +17,12 @@
extern YYSTYPE yylval;
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.)
int yylex();
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.
#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.
#define INDENT_FIELD(FIELD, VAL, ...) \
@ -64,8 +64,8 @@
INDENT_spacing->buf, INDENT_spacing->buf, __VA_ARGS__);
// Print & indent a thing without any newline.
#define INDENT_FIELD_NONL_START(FIELD) \
printf("%s " COL_BWHI FIELD ": " COL_RESET COL_WHI, INDENT_spacing->buf);
#define INDENT_FIELD_EXT_NONL_START(FIELD) \
printf("%s " COL_BWHI FIELD ":\n" COL_RESET COL_WHI, INDENT_spacing->buf);
#define INDENT_FIELD_NONL_END printf( "\n" COL_RESET);
// Print an array A of N things, by calling the function F.

View File

@ -1,9 +1,52 @@
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <stdio.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() {
if (*inp == '\0') return YYEOF;
@ -15,12 +58,7 @@ int yylex() {
// Check for NUM.
if (isdigit(c)) {
int value = c - '0';
while (isdigit(*inp)) {
value = value * 10 + (*inp - '0'); // Accumulate value.
inp++;
}
yylval.intval = value; // Set the token value.
yylval.fval = acc_float(c); // Set the token value.
return NUM;
}
@ -34,4 +72,4 @@ int yylex() {
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/dstr.h"
#include "include/exec.h"
#include "include/lexer.h"
#include "include/util.h"
#include "include/exec.h"
#include "../build/grammars/grammar.tab.h"
@ -31,7 +31,6 @@ int main(int argc, char** argv) {
switch (c) {
case EOF: dstr_destroy(ln); goto lnskip;
case '\n': goto lnend;
default: dstr_appendch(ln, c); log_dbgf("cchar: %c", c);
}
} while (1);
@ -41,14 +40,12 @@ int main(int argc, char** argv) {
log_dbgf("cline: %s", ln->buf);
if (ln->ln > 0) {
// I hope it's null-terminated.
inp = ln->buf;
if (yyparse() == 0)
printf("Parsed successfully!\n");
else
printf("Parse error.\n");
if (yyparse() == 0) printf("Parsed successfully!\n");
else printf("Parse error.\n");
exec_expr();
exec_print(exec_expr(root));
ast_print(root);
}
dstr_destroy(ln);

View File

@ -2,8 +2,8 @@
#include <stdio.h>
#include <string.h>
#include "include/util.h"
#include "include/stack.h"
#include "include/util.h"
Stack* stack_init() {
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]);
}