add getln() function and calculator example

Runtime-allocated strings currently always leak memory, I will
definitely have to fix that.
This commit is contained in:
r4 2021-12-26 11:36:52 +01:00
parent d8b470f0eb
commit dfe1ac90e8
3 changed files with 87 additions and 2 deletions

View File

@ -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)
}
}

57
main.c
View File

@ -53,6 +53,18 @@ static Value fn_int(Value *args) {
case TypeVoid: break; case TypeVoid: break;
case TypeFloat: ret.Int = (ssize_t)args[0].Float; break; case TypeFloat: ret.Int = (ssize_t)args[0].Float; break;
case TypeInt: ret.Int = args[0].Int; 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(); default: ASSERT_UNREACHED();
} }
return ret; return ret;
@ -65,8 +77,20 @@ static Value fn_float(Value *args) {
}; };
switch (args[0].type.kind) { switch (args[0].type.kind) {
case TypeVoid: break; case TypeVoid: break;
case TypeFloat: ret.Float = args[0].Float; break; case TypeFloat: ret.Float = args[0].Float; break;
case TypeInt: ret.Float = (double)args[0].Int; 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(); default: ASSERT_UNREACHED();
} }
return ret; return ret;
@ -92,6 +116,34 @@ static Value fn_sleep(Value *args) {
return (Value){0}; 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) { int main(int argc, const char **argv) {
/* parse arguments */ /* parse arguments */
size_t nargs = argc - 1; 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 = "float", .side_effects = false, .n_args = 1, .func = fn_float, },
{ .name = "pow", .side_effects = false, .n_args = 2, .func = fn_pow, }, { .name = "pow", .side_effects = false, .n_args = 2, .func = fn_pow, },
{ .name = "sleep", .side_effects = true, .n_args = 1, .func = fn_sleep, }, { .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])); IRToks ir = parse(&tokens, funcs, sizeof(funcs) / sizeof(funcs[0]));
if (err) { if (err) {

View File

@ -57,6 +57,16 @@ Value eval_binary(IRInstr instr, const Value *lhs, const Value *rhs) {
case IRLe: res = lhs->Float <= rhs->Float; break; case IRLe: res = lhs->Float <= rhs->Float; break;
default: ASSERT_UNREACHED(); 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 { } else {
set_err("Unsupported types for operation '%s': %s and %s", irinstr_str[instr], type_str[lhs->type.kind], type_str[rhs->type.kind]); 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}; return (Value){0};