Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,7 @@
}
},
]
}
},
"terminal.integrated.fontSize": 16,
"editor.fontSize": 16
}
42 changes: 32 additions & 10 deletions easyc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import child_process from "node:child_process";

const { execFileSync } = child_process;

function indent(str: string, n: number): string {
function indent(str: string, n: number = 1): string {
return str
.split(/\r?\n/)
.map((line) => " ".repeat(n) + line)
Expand Down Expand Up @@ -343,7 +343,7 @@ class ArrayType extends Type {
zero(code: string[]): string {
if (!this.dynamic) return "{0}";
const r = this.hi.context().R();
code.push(`void *${r} AUTOFREE = malloc(sizeof(${this.type.c()}) * (${this.sz()}));`);
code.push(`void *${r} AUTOFREE_ARRAY = malloc(sizeof(${this.type.c()}) * (${this.sz()}));`);
return `{ .data = ${r} }`;
}
typedef = (alias: string) => `typedef ${this.c()} ${alias}`;
Expand Down Expand Up @@ -714,6 +714,7 @@ class SET extends Statement {
`type mismatch in SET: ${type.constructor.name} !== ${this.expression.type.constructor.name} at ${this.token}`
);
}

const value = this.expression.v(code);
code.push(`${reference} = ${value};`);
}
Expand Down Expand Up @@ -858,8 +859,11 @@ class INPUT extends Statement {
const { type, reference } = expand_variable_reference(variable, variable_reference, code);

if (type instanceof StringType) {
code.push(`scanf("%4095s", ${reference}.data);`);
code.push(`${reference}.sz = strlen(${reference}.data);`);
code.push(`{`);
code.push(indent(`char buf[4096];`, 1));
code.push(indent(`scanf("%4095s", buf);`, 1));
code.push(indent(`${reference} = make_string(buf, strlen(buf));`, 1));
code.push(`}`);
} else if (type instanceof IntegerType) code.push(`scanf("%d", &${reference});`);
else if (type instanceof RealType) code.push(`scanf("%lf", &${reference});`);
else throw new GenerateError(`unsupported variable '${variable}' type in INPUT at ${variable.token}`);
Expand Down Expand Up @@ -1058,10 +1062,18 @@ function string_compare(left: Expression, right: Expression, operation: string,
if (operation !== "==" && operation !== "!=") return null;

function is_string_type(e: Expression): [boolean, string | null] {
if (!(e instanceof VariableReference)) return [false, null];
const variable = find_existing_variable(e);
const { type, reference } = expand_variable_reference(variable, e, []);
return [type instanceof StringType, reference];
if (e instanceof VariableReference) {
const variable = find_existing_variable(e);
const { type, reference } = expand_variable_reference(variable, e, []);
return [type instanceof StringType, reference];
}
if (e.type instanceof StringType) return [true, e.v(code)];
if (e instanceof FunctionCall) {
const func = e.context().functions[e.name];
if (!func) throw new GenerateError(`unknown function '${e.name}' at ${e.token}`);
if (func.type instanceof StringType) return [true, e.v(code)];
}
return [false, null];
}

const [left_string, left_reference] = is_string_type(left);
Expand All @@ -1070,7 +1082,15 @@ function string_compare(left: Expression, right: Expression, operation: string,
if (left_string || right_string) {
const cmp = operation === "!=" ? "!=" : "==";
const r = left.context().R();
code.push(`const int ${r} = strcmp(${left_reference}.data, ${right_reference}.data) ${cmp} 0;`);
const left_sz = `${left_reference}.sz`;
const right_sz = `${right_reference}.sz`;
console.log(right_reference);
code.push(
`const int ${r} = ` +
`${left_sz} == ${right_sz} ` +
`&& ` +
`memcmp(${left_reference}.data, ${right_reference}.data, ${left_sz}) ${cmp} 0;`
);
return r;
}
return null;
Expand Down Expand Up @@ -1291,6 +1311,8 @@ function expand_variable_reference(variable: Variable, variable_reference: Varia
let type: Type = variable.type;
let reference = variable.name;

const owner = { name: variable.name, type: variable.type };

for (const part of variable_reference.parts) {
if (part instanceof VariableSubscript) {
if (type instanceof AliasType) type = type.reference_type;
Expand Down Expand Up @@ -1329,7 +1351,7 @@ function expand_variable_reference(variable: Variable, variable_reference: Varia
throw new GenerateError(`unexpected variable reference part '${part}' at ${variable.token}`);
}
}
return { type, reference };
return { type, reference, owner };
}

function find_existing_variable(v: VariableReference): Variable {
Expand Down
2 changes: 1 addition & 1 deletion life.easy
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ PROGRAM Life:

CALL evolution;

CALL rt_pause(0.3);
CALL runtime_pause(0.3);

IF i MOD 10 = 0 THEN
CALL glider(40, 10);
Expand Down
138 changes: 104 additions & 34 deletions runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,7 @@ void free(void *ptr);
#define TRUE 1
#define FALSE 0

#define AUTOFREE __attribute__((cleanup(free_array)))

typedef struct
{
void *data;
} ARRAY;

void free_array(void *ptr)
{
ARRAY *array = (ARRAY *)ptr;
void *data = array->data;
if (data)
{
free(data);
array->data = NULL;
}
}
#define AUTOFREE_ARRAY __attribute__((cleanup(free_array)))

static inline void $sleep(double seconds)
{
Expand All @@ -49,25 +33,111 @@ typedef struct
{
int sz;
int immutable;
char data[4096];
char *data;
} STR;

typedef struct
{
const STR *filename;
int line;
int character;
} Location;
} L;

typedef struct string_list
{
struct string_list *next;
STR *str;
} string_list;

static string_list *strings = NULL;

void print_string(STR s, const char *prefix)
{
char *buf = alloca(s.sz + 1);
memcpy(buf, s.data, s.sz);
buf[s.sz] = '\0';
printf("%s: '%s'\n", prefix, buf);
}

int FIX(double v) { return (int)v; }
STR make_string(const char *data, int sz)
{
void *ptr = malloc(sz);
if (!ptr)
{
fprintf(stderr, "make_string|data: out of memory\n");
exit(1);
}
STR *str = malloc(sizeof(STR));
if (!str)
{
fprintf(stderr, "make_string|str: out of memory\n");
exit(1);
}
*str = (STR){.sz = sz, .data = ptr, .immutable = 0};
memcpy(str->data, data, sz);

string_list *reference = malloc(sizeof(string_list));
if (!reference)
{
fprintf(stderr, "make_string|list: out of memory\n");
exit(1);
}
reference->str = str;
reference->next = strings;
strings = reference;
return *str;
}

void free_strings()
{
string_list *list = strings;
while (list)
{
string_list *next = list->next;
if (list->str->data && !list->str->immutable)
{
memset(list->str->data, 0, list->str->sz);
free(list->str->data);
list->str->data = NULL;

memset(list->str, 0, sizeof(STR));
free(list->str);
list->str = NULL;
}
free(list);
list = next;
}
strings = NULL;
}

typedef struct
{
void *data;
} ARRAY;

void free_array(void *ptr)
{
ARRAY *array = (ARRAY *)ptr;
if (array->data)
{
free(array->data);
array->data = NULL;
}
}

int FIX(double v)
{
return (int)v;
}
double FLOAT(int v) { return (double)v; }
double FLOOR(double v) { return (double)((int)v); }
int LENGTH(STR s) { return s.sz; }

STR CHARACTER(int c)
{
STR v = {.sz = 1, .data = {c, 0}};
return v;
char cbuf = (char)c;
STR s = make_string(&cbuf, 1);
return s;
}

STR SUBSTR(STR from, int start, int length)
Expand Down Expand Up @@ -99,8 +169,7 @@ STR SUBSTR(STR from, int start, int length)
fprintf(stderr, "substr (%s): start + length > size (%d + %d = %d > %d)\n", buf, start, length, start + length, from.sz);
exit(1);
}
STR v = {.sz = length};
memcpy(v.data, from.data + start, length);
STR v = make_string(from.data + start, length);
return v;
}

Expand Down Expand Up @@ -132,20 +201,20 @@ STR $concat(const char *fmt, ...)
else if (*fmt == 'S')
{
const STR *arg = va_arg(args, STR *);
n = arg->sz;
n = (int)sizeof(buf) - sz < arg->sz ? (int)sizeof(buf) - sz : arg->sz;
memcpy(buf + sz, arg->data, n);
}
else if (*fmt == 'A')
{
const STR arg = va_arg(args, STR);
n = arg.sz;
n = (int)sizeof(buf) - sz < arg.sz ? (int)sizeof(buf) - sz : arg.sz;
memcpy(buf + sz, arg.data, n);
}
sz += n;
}
va_end(args);
STR v = {.sz = sz};
memcpy(v.data, buf, sz);

STR v = make_string(buf, sz);
return v;
}

Expand Down Expand Up @@ -190,7 +259,7 @@ void $output(const char *fmt, ...)
putchar('\n');
}

void rt_pause(double seconds)
void runtime_pause(double seconds)
{
$sleep(seconds);
}
Expand All @@ -206,15 +275,16 @@ void $index(int index, int lo, int hi, const STR *filename, int line, int charac

int main_program();

int main()
void $exit()
{
main_program();
return 0;
free_strings();
exit(0);
}

void $exit()
int main()
{
exit(0);
main_program();
$exit();
}

#pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
Expand Down
4 changes: 2 additions & 2 deletions tests/array_1000/x/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ int main_program()
$output("i", b.data[(1000) - (1000)]);
n = 1000;
{
void *$r1 AUTOFREE = malloc(sizeof(double) * (n - n + 1));
void *$r1 AUTOFREE_ARRAY = malloc(sizeof(double) * (n - n + 1));
struct
{
double *data;
} c = { .data = $r1 };
void *$r2 AUTOFREE = malloc(sizeof(struct
void *$r2 AUTOFREE_ARRAY = malloc(sizeof(struct
{
double data[1 - 0 + 1];
}) * (n - n + 1));
Expand Down
2 changes: 1 addition & 1 deletion tests/array_dynamic/x/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ int main_program()
{
sz = 1024;
{
void *$r1 AUTOFREE = malloc(sizeof(int) * (sz - 1 + 1));
void *$r1 AUTOFREE_ARRAY = malloc(sizeof(int) * (sz - 1 + 1));
struct
{
int *data;
Expand Down
Loading