From e46e08fceff29622399855043554635d6e33c3c4 Mon Sep 17 00:00:00 2001 From: thing 1 Date: Fri, 10 Jan 2025 17:38:56 +0000 Subject: init commit --- Makefile | 21 ++++++++++ builtin.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ builtin.h | 3 ++ builtin.o | Bin 0 -> 10456 bytes eval.c | 69 +++++++++++++++++++++++++++++++ eval.h | 18 +++++++++ eval.o | Bin 0 -> 8416 bytes lucky | Bin 0 -> 34784 bytes lucky.c | 32 +++++++++++++++ lucky.o | Bin 0 -> 7672 bytes parser.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++ parser.h | 36 +++++++++++++++++ parser.o | Bin 0 -> 10200 bytes stack.c | 45 +++++++++++++++++++++ stack.h | 14 +++++++ stack.o | Bin 0 -> 4904 bytes test.lk | 3 ++ 17 files changed, 493 insertions(+) create mode 100644 Makefile create mode 100644 builtin.c create mode 100644 builtin.h create mode 100644 builtin.o create mode 100644 eval.c create mode 100644 eval.h create mode 100644 eval.o create mode 100755 lucky create mode 100644 lucky.c create mode 100644 lucky.o create mode 100644 parser.c create mode 100644 parser.h create mode 100644 parser.o create mode 100644 stack.c create mode 100644 stack.h create mode 100644 stack.o create mode 100644 test.lk diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..773b473 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +CC=cc +CFLAGS=-ggdb -Wall +LIBS= + +SRC = stack.c parser.c eval.c builtin.c lucky.c +OBJ = ${SRC:.c=.o} + +all: lucky + +.c.o: + ${CC} -c ${CFLAGS} $< +lucky: ${OBJ} + ${CC} -o $@ ${OBJ} ${LIBS} +install: all + cp lucky /usr/local/bin/lucky +clean: + rm -rf lucky *.o +uninstall: + rm /usr/local/bin/lucky + +.PHONY: all clean install uninstall diff --git a/builtin.c b/builtin.c new file mode 100644 index 0000000..89995a3 --- /dev/null +++ b/builtin.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include "parser.h" +#include "eval.h" + +bool arithmetic(luckytree *tree, luckyval *out){ + if (strcmp(tree->function, "+") == 0){ + argcounterror(tree, 2); + if (tree->arguments->type == LUCKYINT && tree->arguments->nextelement->type == LUCKYINT){ + out->i = tree->arguments->i + tree->arguments->nextelement->i; + out->type = LUCKYINT; + }else if (tree->arguments->type == LUCKYFLOAT && tree->arguments->nextelement->type == LUCKYFLOAT){ + out->f = tree->arguments->f + tree->arguments->nextelement->f; + out->type = LUCKYFLOAT; + }else if (tree->arguments->type == LUCKYFLOAT && tree->arguments->nextelement->type == LUCKYINT){ + out->f = tree->arguments->f + tree->arguments->nextelement->i; + out->type = LUCKYFLOAT; + }else if (tree->arguments->type == LUCKYINT && tree->arguments->nextelement->type == LUCKYFLOAT){ + out->f = tree->arguments->i + tree->arguments->nextelement->f; + out->type = LUCKYFLOAT; + } + else { + printf("invalid types given!\n"); + exit(1); + } + } + else if (strcmp(tree->function, "-") == 0){ + argcounterror(tree, 2); + if (tree->arguments->type == LUCKYINT && tree->arguments->nextelement->type == LUCKYINT){ + out->i = tree->arguments->i - tree->arguments->nextelement->i; + out->type = LUCKYINT; + }else if (tree->arguments->type == LUCKYFLOAT && tree->arguments->nextelement->type == LUCKYFLOAT){ + out->f = tree->arguments->f - tree->arguments->nextelement->f; + out->type = LUCKYFLOAT; + }else if (tree->arguments->type == LUCKYFLOAT && tree->arguments->nextelement->type == LUCKYINT){ + out->f = tree->arguments->f - tree->arguments->nextelement->i; + out->type = LUCKYFLOAT; + }else if (tree->arguments->type == LUCKYINT && tree->arguments->nextelement->type == LUCKYFLOAT){ + out->f = tree->arguments->i - tree->arguments->nextelement->f; + out->type = LUCKYFLOAT; + } + else { + printf("invalid types given!\n"); + exit(1); + } + } + else if (strcmp(tree->function, "*") == 0){ + argcounterror(tree, 2); + if (tree->arguments->type == LUCKYINT && tree->arguments->nextelement->type == LUCKYINT){ + out->i = tree->arguments->i * tree->arguments->nextelement->i; + out->type = LUCKYINT; + }else if (tree->arguments->type == LUCKYFLOAT && tree->arguments->nextelement->type == LUCKYFLOAT){ + out->f = tree->arguments->f * tree->arguments->nextelement->f; + out->type = LUCKYFLOAT; + }else if (tree->arguments->type == LUCKYFLOAT && tree->arguments->nextelement->type == LUCKYINT){ + out->f = tree->arguments->f * tree->arguments->nextelement->i; + out->type = LUCKYFLOAT; + }else if (tree->arguments->type == LUCKYINT && tree->arguments->nextelement->type == LUCKYFLOAT){ + out->f = tree->arguments->i * tree->arguments->nextelement->f; + out->type = LUCKYFLOAT; + } + else { + printf("invalid types given!\n"); + exit(1); + } + } + else if (strcmp(tree->function, "/") == 0){ + argcounterror(tree, 2); + if (tree->arguments->type == LUCKYINT && tree->arguments->nextelement->type == LUCKYINT){ + out->i = tree->arguments->i / tree->arguments->nextelement->i; + out->type = LUCKYINT; + }else if (tree->arguments->type == LUCKYFLOAT && tree->arguments->nextelement->type == LUCKYFLOAT){ + out->f = tree->arguments->f / tree->arguments->nextelement->f; + out->type = LUCKYFLOAT; + }else if (tree->arguments->type == LUCKYFLOAT && tree->arguments->nextelement->type == LUCKYINT){ + out->f = tree->arguments->f / tree->arguments->nextelement->i; + out->type = LUCKYFLOAT; + }else if (tree->arguments->type == LUCKYINT && tree->arguments->nextelement->type == LUCKYFLOAT){ + out->f = tree->arguments->i / tree->arguments->nextelement->f; + out->type = LUCKYFLOAT; + } + else { + printf("invalid types given!\n"); + exit(1); + } + } + else return false; + return true; +} + +bool variableops(luckytree *tree, luckyval *out){ + if (strcmp(tree->function, "let") == 0){ + argcounterror(tree, 2); + if (tree->arguments->type == LUCKYVAR) { + variables[varcount] = malloc(sizeof(luckyvar)); + variables[varcount]->name = strdup(tree->arguments->var); + + variables[varcount]->val = malloc(sizeof(luckyval)); + memcpy(variables[varcount]->val, tree->arguments->nextelement, sizeof(luckyval)); + varcount++; + } else { + printf("expected var name as the first argument!\n"); + exit(1); + } + } + else return false; + return true; +} + +bool io(luckytree *tree, luckyval *out){ + if (strcmp(tree->function, "print") == 0){ + argcounterror(tree, 1); + if (tree->arguments->type == LUCKYINT) + printf("%d\n", tree->arguments->i); + if (tree->arguments->type == LUCKYFLOAT) + printf("%f\n", tree->arguments->f); + } + else if (strcmp(tree->function, "readint") == 0){ + argcounterror(tree, 0); + int i; + scanf("%d", &i); + out->i = i; + out->type = LUCKYINT; + } + else if (strcmp(tree->function, "readfloat") == 0){ + argcounterror(tree, 0); + float f; + scanf("%f", &f); + out->f = f; + out->type = LUCKYFLOAT; + } + else return false; + return true; +} diff --git a/builtin.h b/builtin.h new file mode 100644 index 0000000..acbfd31 --- /dev/null +++ b/builtin.h @@ -0,0 +1,3 @@ +bool arithmetic(luckytree *tree, luckyval *out); +bool variableops(luckytree *tree, luckyval *out); +bool io(luckytree *tree, luckyval *out); diff --git a/builtin.o b/builtin.o new file mode 100644 index 0000000..5a57c5b Binary files /dev/null and b/builtin.o differ diff --git a/eval.c b/eval.c new file mode 100644 index 0000000..4f4b1e2 --- /dev/null +++ b/eval.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include "parser.h" +#include "builtin.h" +#include "eval.h" + +int varcount = 0; +luckyvar *variables[10000]; + +int funccount= 0; +luckytree *functions[10000]; + +int argcount(luckyval *tree){ + if (tree == NULL) return 0; + else return 1 + argcount(tree->nextelement); +} + +bool checkargcount(luckytree *tree, int i){ + return !(argcount(tree->arguments) == i); +} + +void argcounterror(luckytree *tree, int expected){ + if (checkargcount(tree, expected)) { + printf("expected %d args to function %s, got %d\n",expected, tree->function, argcount(tree->arguments)); + exit(1); + } +} + +luckyval *lookupvar(char *name){ + for (int i = 0; i < 10000; i++){ + if (variables[i] != NULL && strcmp(variables[i]->name, name) == 0){ + return variables[i]->val; + } + } + printf("no such variable %s exists!\n", name); + exit(1); +} + +luckyval *eval(luckytree *tree){ + int i = 0; + for (luckyval *current = tree->arguments; i < argcount(tree->arguments); current = current->nextelement){ + if (current->type == LUCKYTREE){ + luckyval *var = malloc(sizeof(luckyval)); + var = eval(current->tree); + memcpy(¤t->d, &var->d, sizeof(double)); + current->type = var->type; + free(var); + } + else if (strcmp(tree->function, "let") != 0) { + if (current->type == LUCKYVAR){ + luckyval *tmp = lookupvar(current->var); + memcpy(¤t->d, &tmp->d, sizeof(double)); + current->type = tmp->type; + } + } + i++; + } + + luckyval *out = malloc(sizeof(luckyval)); + + if (arithmetic(tree, out)) return out; + else if (io(tree, out)) return out; + else if (variableops(tree, out)) return out; + + printf("Unknown function!\n"); + exit(1); +} diff --git a/eval.h b/eval.h new file mode 100644 index 0000000..fa6523a --- /dev/null +++ b/eval.h @@ -0,0 +1,18 @@ +typedef struct luckyvar luckyvar; + +typedef struct luckyvar { + luckyval *val; + char *name; +} luckyvar; + + +int argcount(luckyval *tree); +bool checkargcount(luckytree *tree, int i); +void argcounterror(luckytree *tree, int expected); +luckyval *eval(luckytree *tree); + +extern luckyvar *variables[10000]; +extern int varcount; + +extern luckytree *functions[10000]; +extern int funccount; diff --git a/eval.o b/eval.o new file mode 100644 index 0000000..3a40933 Binary files /dev/null and b/eval.o differ diff --git a/lucky b/lucky new file mode 100755 index 0000000..59df94c Binary files /dev/null and b/lucky differ diff --git a/lucky.c b/lucky.c new file mode 100644 index 0000000..7566895 --- /dev/null +++ b/lucky.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include "parser.h" +#include "eval.h" + +void strip(char *s, char c){ + for (int i = 0; i < strlen(s); i++){ + if (s[i] == c) { + s[i] = 0; + return; + } + } + return; + +} + +int main(int argc, char **argv){ + FILE *f = fopen(argv[1], "r"); + char *line = malloc(256); + while (fgets(line, 256, f) != NULL){ + strip(line, '\n'); + if (strlen(line) == 0) goto skip; + + luckytree *tree = parse(line); + luckyval *ret = eval(tree); + free(tree); + free(ret); +skip: + } +} diff --git a/lucky.o b/lucky.o new file mode 100644 index 0000000..47324b3 Binary files /dev/null and b/lucky.o differ diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..9bbc50b --- /dev/null +++ b/parser.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include "stack.h" +#include "parser.h" +#include "eval.h" + +static unsigned int jumpdist; + +static char *readexpr(char *expr){ + char *out = malloc(strlen(expr+1)); + char *c = expr; + stack *s = push(NULL, *c); + int i; + + for (i = 0; s->len != 0; i++){ + out[i] = *c; + c++; + if (*c == '(') s = push(s, '('); + else if (*c == ')' && peek(s) == '(') pop(s); + } + cleanstack(s); + + out[i] = ')'; + out[i+1] = 0; + out = realloc(out, strlen(out)); + jumpdist = i+1; + return out; +} + +static char *readval(char *expr){ + char *out = strdup(expr); + char *gap = strchr(out, ' '); + if (gap == NULL) gap = strchr(out, ')'); + jumpdist = (gap - out)+1; + *gap = 0; + out = realloc(out, strlen(out)); + return out; +} + +static luckyval *readargs(char *expr){ + luckyval *head = malloc(sizeof(luckyval)); + + if (*expr != ')' && expr[0] != 0){ + if (expr[0] == '(' ){ // nested function + char *subexpr = readexpr(expr); + expr += jumpdist + 1; + head->tree = parse(subexpr); + head->type = LUCKYTREE; + free(subexpr); + } + else if (strchr(expr, '.') != NULL){ // float + char *val = readval(expr); + expr += jumpdist; + head->f = atof(val); + head->type = LUCKYFLOAT; + free(val); + } + else if (isdigit(expr[0])){ // int + char *val = readval(expr); + expr += jumpdist; + head->i = atoi(val); + head->type = LUCKYINT; + free(val); + } + else { // var name + char *val = readval(expr); + expr += jumpdist; + head->var = strdup(val); + head->type = LUCKYVAR; + } + } else return NULL; + + head->nextelement = readargs(expr); + return head; +} + +luckytree *parse(char *expr){ + char *c = expr; + stack *s = push(NULL, *c); + while (*c != 0){ + c++; + if (*c == '(') s = push(s, '('); + else if (*c == ')' && peek(s) == '(') pop(s); + } + if (s->len != 0){ + printf("%s\n", expr); + for (int i = 0; i < (c - expr) - 1; i++) printf(" "); + printf("^\n"); + printf("bracket mismatch!\n"); + exit(1); + } + cleanstack(s); + + luckytree *tree = malloc(sizeof(luckytree)); + + int funcnamelen; + if (strchr(expr+1, ' ') == NULL) + funcnamelen = (strchr(expr+1, ')') - expr) - 1; + else + funcnamelen = (strchr(expr+1, ' ') - expr) - 1; + + tree->function = malloc(funcnamelen + 1); + + memcpy(tree->function, expr + 1, funcnamelen); + tree->function[funcnamelen] = 0; + + expr += funcnamelen + 2; + + tree->arguments = readargs(expr); + + return tree; +} + diff --git a/parser.h b/parser.h new file mode 100644 index 0000000..3f6e2e3 --- /dev/null +++ b/parser.h @@ -0,0 +1,36 @@ +typedef struct luckyval luckyval; +typedef struct luckytree luckytree; + +typedef enum luckytypes { + LUCKYCHAR, + LUCKYINT, + LUCKYLONG, + LUCKYFLOAT, + LUCKYDOUBLE, + LUCKYARR, + LUCKYVAR, + LUCKYTREE, +} luckytypes; + +typedef struct luckyval { + union { + char c; + int i; + long l; + float f; + double d; + luckyval *arr; + luckytree *tree; + char *var; + }; + luckytypes type; + luckyval *nextelement; +} luckyval; + +typedef struct luckytree { + char *function; + luckyval *arguments; + luckytree *next; +} luckytree; + +luckytree *parse(char *expr); diff --git a/parser.o b/parser.o new file mode 100644 index 0000000..ec08f0c Binary files /dev/null and b/parser.o differ diff --git a/stack.c b/stack.c new file mode 100644 index 0000000..c07c7fc --- /dev/null +++ b/stack.c @@ -0,0 +1,45 @@ +#include + +typedef struct stack stack; + +typedef struct stack { + char *tape; + int len; + char *ptr; +} stack; + +stack *push(stack *s, char c){ + if (s == NULL) { + stack *outstack = malloc(sizeof(stack)); + outstack->tape = malloc(1); + outstack->tape[0] = c; + outstack->ptr = outstack->tape; + outstack->len = 1; + return outstack; + } + s->len++; + s->ptr++; + s->tape = realloc(s->tape, s->len); + *s->ptr = c; + + return s; +} + +char pop(stack *s){ + char c = *s->ptr; + *s->ptr = 0; + s->len--; + s->ptr--; + s->tape = realloc(s->tape, s->len); + + return c; +} + +char peek(stack *s){ + return *s->ptr; +} + +void cleanstack(stack *s){ + free(s->tape); + free(s); +} diff --git a/stack.h b/stack.h new file mode 100644 index 0000000..ab3491b --- /dev/null +++ b/stack.h @@ -0,0 +1,14 @@ +#include + +typedef struct stack stack; + +typedef struct stack { + char *tape; + int len; + char *ptr; +} stack; + +stack *push(stack *s, char c); +char pop(stack *s); +char peek(stack *s); +void cleanstack(stack *s); diff --git a/stack.o b/stack.o new file mode 100644 index 0000000..e4d1968 Binary files /dev/null and b/stack.o differ diff --git a/test.lk b/test.lk new file mode 100644 index 0000000..77233bc --- /dev/null +++ b/test.lk @@ -0,0 +1,3 @@ +(let a (readint)) +(let b (+ a 2)) +(print b -- cgit v1.2.3