From dfe1ac90e89cb83254eeb14c5ebb3b64d83bc679 Mon Sep 17 00:00:00 2001 From: r4 Date: Sun, 26 Dec 2021 11:36:52 +0100 Subject: [PATCH] add getln() function and calculator example Runtime-allocated strings currently always leak memory, I will definitely have to fix that. --- examples/calculator.script | 22 +++++++++++++++ main.c | 57 ++++++++++++++++++++++++++++++++++++-- runtime.c | 10 +++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 examples/calculator.script diff --git a/examples/calculator.script b/examples/calculator.script new file mode 100644 index 0000000..2f7878d --- /dev/null +++ b/examples/calculator.script @@ -0,0 +1,22 @@ +put("Enter an operation (+, -, *, /): ") +op := getln() +if (!(op == "+" || op == "-" || op == "*" || op == "/")) { + put("Unknown operation: ") + putln(op) +} else { + put("1st number: ") + n1 := float(getln()) + put("2nd number: ") + n2 := float(getln()) + + put("Result: ") + if (op == "+") { + putln(n1 + n2) + } else if (op == "-") { + putln(n1 - n2) + } else if (op == "*") { + putln(n1 * n2) + } else if (op == "/") { + putln(n1 / n2) + } +} diff --git a/main.c b/main.c index cbb7f28..6c94973 100644 --- a/main.c +++ b/main.c @@ -53,6 +53,18 @@ static Value fn_int(Value *args) { case TypeVoid: break; case TypeFloat: ret.Int = (ssize_t)args[0].Float; break; case TypeInt: ret.Int = args[0].Int; break; + case TypeBool: ret.Int = (ssize_t)args[0].Bool; break; + case TypeArr: + if (args[0].Arr.is_string && args[0].Arr.type.kind == TypeChar) { + ssize_t endpos; + ret.Int = stoimax((char*)args[0].Arr.vals, args[0].Arr.len, 10, &endpos); + if (endpos != -1) { + set_err("Error converting from string to int"); + return (Value){0}; + } + } else + ASSERT_UNREACHED(); + break; default: ASSERT_UNREACHED(); } return ret; @@ -65,8 +77,20 @@ static Value fn_float(Value *args) { }; switch (args[0].type.kind) { case TypeVoid: break; - case TypeFloat: ret.Float = args[0].Float; break; - case TypeInt: ret.Float = (double)args[0].Int; break; + case TypeFloat: ret.Float = args[0].Float; break; + case TypeInt: ret.Float = (double)args[0].Int; break; + case TypeBool: ret.Float = (double)args[0].Bool; break; + case TypeArr: + if (args[0].Arr.is_string && args[0].Arr.type.kind == TypeChar) { + ssize_t endpos; + ret.Float = stod((char*)args[0].Arr.vals, args[0].Arr.len, &endpos); + if (endpos != -1) { + set_err("Error converting from string to float"); + return (Value){0}; + } + } else + ASSERT_UNREACHED(); + break; default: ASSERT_UNREACHED(); } return ret; @@ -92,6 +116,34 @@ static Value fn_sleep(Value *args) { return (Value){0}; } +static Value fn_getln(Value *args) { + (void)args; + + char *line = xmalloc(64); + size_t len = 0, cap = 64; + for (;;) { + int c = fgetc(stdin); + if (c == EOF) + break; + else if (c == '\n') + break; + if (len+1 > cap) + line = xrealloc(line, (cap *= 2)); + line[len++] = c; + } + + return (Value){ + .type.kind = TypeArr, + .Arr = { + .is_string = true, + .type.kind = TypeChar, + .vals = line, + .len = len, + .cap = cap, + }, + }; +} + int main(int argc, const char **argv) { /* parse arguments */ size_t nargs = argc - 1; @@ -157,6 +209,7 @@ int main(int argc, const char **argv) { { .name = "float", .side_effects = false, .n_args = 1, .func = fn_float, }, { .name = "pow", .side_effects = false, .n_args = 2, .func = fn_pow, }, { .name = "sleep", .side_effects = true, .n_args = 1, .func = fn_sleep, }, + { .name = "getln", .side_effects = true, .n_args = 0, .func = fn_getln, }, }; IRToks ir = parse(&tokens, funcs, sizeof(funcs) / sizeof(funcs[0])); if (err) { diff --git a/runtime.c b/runtime.c index 8c6d8a3..cfe6d5b 100644 --- a/runtime.c +++ b/runtime.c @@ -57,6 +57,16 @@ Value eval_binary(IRInstr instr, const Value *lhs, const Value *rhs) { case IRLe: res = lhs->Float <= rhs->Float; break; default: ASSERT_UNREACHED(); }; + } else if (lhs->type.kind == TypeArr && lhs->Arr.type.kind == TypeChar && lhs->Arr.is_string && + rhs->type.kind == TypeArr && rhs->Arr.type.kind == TypeChar && rhs->Arr.is_string) { + switch (instr) { + case IREq: + res = lhs->Arr.len == rhs->Arr.len ? strncmp(lhs->Arr.vals, rhs->Arr.vals, lhs->Arr.len) == 0 : false; + break; + default: + set_err("String operation '%s' not supported", irinstr_str[instr]); + break; + }; } else { set_err("Unsupported types for operation '%s': %s and %s", irinstr_str[instr], type_str[lhs->type.kind], type_str[rhs->type.kind]); return (Value){0};