More error handling - locations of refs to undefined symbols.

This commit is contained in:
Stephen Dolan committed 2012-09-11 12:24:54 +01:00
1 parent 4c7bede5a4
commit 062a6aa6d7
5 files changed
+90 -43

No files matched your search

+32 -8
View File
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include "opcode.h"
#include "compile.h"
#include "locfile.h"
struct inst {
struct inst* next;
@@ -18,6 +18,8 @@ struct inst {
struct cfunction* cfunc;
} imm;
location source;
// Binding
// An instruction requiring binding (for parameters/variables)
// is in one of three states:
@@ -45,6 +47,7 @@ static inst* inst_new(opcode op) {
i->bound_by = 0;
i->symbol = 0;
i->subfn = gen_noop();
i->source = UNKNOWN_LOCATION;
return i;
}
@@ -82,6 +85,16 @@ static inst* block_take(block* b) {
return i;
}
block gen_location(location loc, block b) {
for (inst* i = b.first; i; i = i->next) {
if (i->source.start == UNKNOWN_LOCATION.start &&
i->source.end == UNKNOWN_LOCATION.end) {
i->source = loc;
}
}
return b;
}
block gen_noop() {
block b = {0,0};
return b;
@@ -429,7 +442,8 @@ static int count_cfunctions(block b) {
return n;
}
static void compile(struct bytecode* bc, block b) {
static int compile(struct locfile* locations, struct bytecode* bc, block b) {
int errors = 0;
int pos = 0;
int var_frame_idx = 0;
bc->nsubfunctions = 0;
@@ -442,7 +456,10 @@ static void compile(struct bytecode* bc, block b) {
int opflags = opcode_describe(curr->op)->flags;
if (opflags & OP_HAS_BINDING) {
assert(curr->bound_by && "unbound term");
if (!curr->bound_by) {
locfile_locate(locations, curr->source, "error: %s is not defined", curr->symbol);
errors++;
}
}
if ((opflags & OP_HAS_VARIABLE) &&
curr->bound_by == curr) {
@@ -472,7 +489,7 @@ static void compile(struct bytecode* bc, block b) {
bc->subfunctions[curr->imm.intval] = subfn;
subfn->globals = bc->globals;
subfn->parent = bc;
compile(subfn, curr->subfn);
errors += compile(locations, subfn, curr->subfn);
}
} else {
bc->subfunctions = 0;
@@ -483,7 +500,7 @@ static void compile(struct bytecode* bc, block b) {
pos = 0;
jv constant_pool = jv_array();
int maxvar = -1;
for (inst* curr = b.first; curr; curr = curr->next) {
if (!errors) for (inst* curr = b.first; curr; curr = curr->next) {
const struct opcode_description* op = opcode_describe(curr->op);
if (op->length == 0)
continue;
@@ -551,18 +568,25 @@ static void compile(struct bytecode* bc, block b) {
}
bc->constants = constant_pool;
bc->nlocals = maxvar + 2; // FIXME: frames of size zero?
return errors;
}
struct bytecode* block_compile(block b) {
int block_compile(block b, struct locfile* locations, struct bytecode** out) {
struct bytecode* bc = malloc(sizeof(struct bytecode));
bc->parent = 0;
bc->globals = malloc(sizeof(struct symbol_table));
int ncfunc = count_cfunctions(b);
bc->globals->ncfunctions = 0;
bc->globals->cfunctions = malloc(sizeof(struct cfunction) * ncfunc);
compile(bc, b);
int nerrors = compile(locations, bc, b);
assert(bc->globals->ncfunctions == ncfunc);
return bc;
if (nerrors > 0) {
bytecode_free(bc);
*out = 0;
} else {
*out = bc;
}
return nerrors;
}
void block_free(block b) {
+4 -1
View File
@@ -1,6 +1,7 @@
#include <stdint.h>
#include "bytecode.h"
#include "opcode.h"
#include "locfile.h"
struct inst;
typedef struct inst inst;
@@ -11,6 +12,8 @@ typedef struct block {
inst* last;
} block;
block gen_location(location, block);
block gen_noop();
block gen_op_simple(opcode op);
block gen_op_const(opcode op, jv constant);
@@ -39,7 +42,7 @@ void block_append(block* b, block b2);
block block_join(block a, block b);
block block_bind(block binder, block body, int bindflags);
struct bytecode* block_compile(block);
int block_compile(block, struct locfile*, struct bytecode**);
void block_free(block);
+21 -5
View File
@@ -1,10 +1,15 @@
#ifndef _LOCFILE_H
#define _LOCFILE_H
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
typedef struct {
int start, end;
} location;
static const location UNKNOWN_LOCATION = {-1, -1};
struct locfile {
const char* data;
int length;
@@ -48,15 +53,26 @@ static int locfile_line_length(struct locfile* l, int line) {
return l->linemap[line+1] - l->linemap[line];
}
static void locfile_locate(struct locfile* l, location loc) {
static void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) {
va_list fmtargs;
va_start(fmtargs, fmt);
vfprintf(stderr, fmt, fmtargs);
va_end(fmtargs);
fprintf(stderr, "\n");
if (loc.start == -1) {
fprintf(stderr, "<unknown location>\n");
return;
}
int startline = locfile_get_line(l, loc.start);
int offset = l->linemap[startline];
printf("%.*s\n", locfile_line_length(l, startline), l->data + offset);
printf("%*s", loc.start - offset, "");
fprintf(stderr, "%.*s\n", locfile_line_length(l, startline), l->data + offset);
fprintf(stderr, "%*s", loc.start - offset, "");
for (int i = loc.start;
i < loc.end && i < offset + locfile_line_length(l, startline);
i++){
printf("^");
fprintf(stderr, "^");
}
printf("\n");
fprintf(stderr, "\n");
}
#endif
+26 -19
View File
@@ -1,15 +1,36 @@
#include <stdio.h>
#include <string.h>
#include "compile.h"
#include "parser.tab.h"
#include "builtin.h"
#include "jv.h"
#include "locfile.h"
int compile(const char* str, block* answer);
int jq_parse(struct locfile* source, block* answer);
void jq_init(struct bytecode* bc, jv value);
jv jq_next();
void jq_teardown();
struct bytecode* jq_compile(const char* str) {
struct locfile locations;
locfile_init(&locations, str, strlen(str));
block program;
struct bytecode* bc = 0;
int nerrors = jq_parse(&locations, &program);
if (nerrors == 0) {
block_append(&program, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK)));
program = gen_cbinding(&builtins, program);
nerrors = block_compile(program, &locations, &bc);
block_free(program);
}
if (nerrors) {
fprintf(stderr, "%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error");
}
locfile_free(&locations);
return bc;
}
void run_program(struct bytecode* bc) {
#if JQ_DEBUG
@@ -52,14 +73,8 @@ void run_tests() {
if (skipline(buf)) continue;
printf("Testing %s\n", buf);
int pass = 1;
block program;
int nerrors = compile(buf, &program);
assert(nerrors == 0);
block_append(&program, gen_op_simple(YIELD));
block_append(&program, gen_op_simple(BACKTRACK));
program = gen_cbinding(&builtins, program);
struct bytecode* bc = block_compile(program);
block_free(program);
struct bytecode* bc = jq_compile(buf);
assert(bc);
printf("Disassembly:\n");
dump_disassembly(2, bc);
printf("\n");
@@ -111,16 +126,8 @@ void run_tests() {
int main(int argc, char* argv[]) {
if (argc == 1) { run_tests(); return 0; }
block blk;
int nerrors = compile(argv[1], &blk);
if (nerrors > 0) {
printf("%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error");
return 1;
}
block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK)));
blk = gen_cbinding(&builtins, blk);
struct bytecode* bc = block_compile(blk);
block_free(blk);
struct bytecode* bc = jq_compile(argv[1]);
if (!bc) return 1;
run_program(bc);
bytecode_free(bc);
return 0;
+7 -10
View File
@@ -83,8 +83,7 @@
void yyerror(YYLTYPE* loc, block* answer, int* errors,
struct locfile* locations, yyscan_t lexer, const char *s){
(*errors)++;
printf("error: %s\n", s);
locfile_locate(locations, *loc);
locfile_locate(locations, *loc, "error: %s", s);
}
int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors,
@@ -293,11 +292,11 @@ LITERAL {
block_append(&$$, gen_op_simple(POP));
} |
'$' IDENT {
$$ = gen_op_var_unbound(LOADV, jv_string_value($2));
$$ = gen_location(@$, gen_op_var_unbound(LOADV, jv_string_value($2)));
jv_free($2);
} |
IDENT {
$$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)));
$$ = gen_location(@$, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, jv_string_value($1))));
jv_free($1);
} |
IDENT '(' Exp ')' {
@@ -307,6 +306,7 @@ IDENT '(' Exp ')' {
"lambda",
block_join($3, gen_op_simple(RET))),
gen_noop(), OP_IS_CALL_PSEUDO)));
$$ = gen_location(@1, $$);
jv_free($1);
} |
'(' error ')' { $$ = gen_noop(); } |
@@ -342,17 +342,14 @@ MkDictPair
| '(' error ')' ':' ExpD { $$ = $5; }
%%
int compile(const char* str, block* answer) {
int jq_parse(struct locfile* locations, block* answer) {
yyscan_t scanner;
YY_BUFFER_STATE buf;
jq_yylex_init_extra(0, &scanner);
buf = jq_yy_scan_string(str, scanner);
buf = jq_yy_scan_bytes(locations->data, locations->length, scanner);
int errors = 0;
struct locfile locations;
locfile_init(&locations, str, strlen(str));
*answer = gen_noop();
yyparse(answer, &errors, &locations, scanner);
locfile_free(&locations);
yyparse(answer, &errors, locations, scanner);
jq_yy_delete_buffer(buf, scanner);
jq_yylex_destroy(scanner);
if (errors > 0) {