15 int Location::global_error_count = 0;
18 if (exit_pc.
valid())
return exit_pc;
25 static Location dummy(0,
"no_idea_where");
29 void Location::print_internal(
const char *msg,
const char *msg_type,
const char *launcher_file,
int launcher_line)
const {
30 #if defined(MASK_ERRORS)
31 fputs(
"(disabled) ", stderr);
34 fprint_location(stderr);
37 fputs(msg_type, stderr);
46 fputs(
" (cursor ", stderr);
55 #if defined(MASK_ERRORS)
56 fputs(
"(disabled) ", stderr);
58 fputs(
"../AISC/", stderr);
59 fprint_location(launcher_file, launcher_line, stderr);
60 fprintf(stderr,
"%s was launched from here\n", msg_type);
64 #define ERRBUFSIZE 500
69 if (!errbuf) { errbuf = (
char*)malloc(
ERRBUFSIZE+1); }
73 int chars = vsprintf(errbuf, format, argPtr);
75 fprintf(stderr,
"%s:%i: Error: Buffer overflow!\n", __FILE__, __LINE__);
89 while (count--)
fputc(
'\t', out);
96 const Token *first = list->first_token();
98 if (tok != first)
fputc(
',', out);
100 if (tok->is_block()) {
101 fprintf(out,
"'%s'={\n", tok->get_key());
103 if (content)
write_aisc(content, out, indentation + 1);
108 fprintf(out,
"\t'%s'=(~%s~)",
110 tok->has_value() ? tok->get_value() :
"");
122 void Interpreter::define_fun(
const char *name,
const Code *co) {
123 const Code *exists = find_fun(name);
130 sprintf(buffer,
"%li", (
long)co);
131 functions->
write(name, buffer);
135 const Code *Interpreter::find_fun(
const char *name) {
136 const char *fn = functions->
read(name);
141 int Interpreter::do_dumpdata(
const char *filename) {
148 printf(
"Dumping data to '%s'\n", filename);
149 out = fopen(filename,
"wt");
151 printf_error(
at(),
"cant write to file '%s' (DUMPDATA)", filename);
159 if (filename[0]) fclose(out);
163 int Interpreter::do_data(
const char *
str) {
164 if (strlen(str) < 2) {
169 if (!set_data(str, 4)) {
176 int Interpreter::do_indent(
const char *str) {
177 int diff = atoi(str);
179 int new_indent = indent+
diff;
182 printf_error(
at(),
"invalid resulting indentation %i", new_indent);
190 int Interpreter::do_tabstop(
const char *str) {
192 if ((ts < 1) || (ts > 1024)) {
206 void init(
const char *a) { strtok_arg = args = strdup(a); }
209 ArgParser(
const char *arguments,
const Code *co) : loc(co->source) { init(arguments); }
212 const char *
get(
const char *paramDescription) {
213 const char *res = strtok(strtok_arg,
" \t,;\n");
215 if (!res)
printf_error(&loc,
"Missing argument '%s'", paramDescription);
220 int Interpreter::do_tab(
const char *str) {
223 const char *s1 = args.get(
"TABCOUNT");
225 const char *s2 = args.get(
"TABVALUE");
228 if ((ts < 0) || (ts > 9))
print_error(
at(),
"wrong TABCOUNT");
231 if ((val < 0) || (val > 1000))
print_error(
at(),
"wrong TABVALUE");
233 current_formatter().
set_tab(ts, val);
242 int Interpreter::do_open(
const char *str) {
245 const char *fileID = args.get(
"fileID");
247 const char *fn = args.get(
"filename");
248 if (strlen(fn) < 3)
printf_error(
at(),
"Filename '%s' too short (<3)", fn);
250 Output *alreadyOpen = find_output_for_ID(fileID);
251 if (alreadyOpen)
printf_error(
at(),
"File '%s' already opened", fileID);
255 if (!
output[i].inUse())
break;
257 if (i == OPENFILES)
print_error(
at(),
"Too many open files");
259 FILE *file = fopen(fn,
"wt");
261 output[i].assign(file, fileID, fn,
at());
272 int Interpreter::do_close(
const char *str) {
274 const char *fileID = args.get(
"fileID");
277 Output *known = find_output_for_ID(fileID);
287 int Interpreter::do_out(
const char *str) {
289 const char *fileID = args.get(
"fileID");
292 Output *known = find_output_for_ID(fileID);
294 current_output = known;
303 const char *
start = strstr(code,
"$(");
305 print_error(at,
"expected to see '$(' while parsing for ident/selector");
308 const char *end = strchr(start+2,
')');
310 print_error(at,
"missing closing ')' after ident/selector");
324 int Interpreter::do_moveto(
const char *str) {
342 void var_ref::const_violation() {
344 "Attempt to modify write-protected variable '%s'", e->
key);
347 int Interpreter::do_makeconst(
const char *str) {
354 printf_error(
at(),
"undefined Ident '%s' in CONST (use CREATE first)", ident);
365 int Interpreter::do_set(
const char *str) {
371 printf_error(
at(),
"undefined Ident '%s' in SET (use CREATE first)", ident);
379 err = var.
write(str);
386 int Interpreter::do_create(
const char *str) {
388 const char *def = read_var(var);
391 if (def)
printf_error(
at(),
"Ident '%s' in CREATE already defined", var);
405 int Interpreter::do_if(
const char *str) {
407 bool condition =
false;
410 const char *cursor = strpbrk(str,
"=~<");
411 if (!cursor) condition =
true;
415 bool negate = cursor[-1] ==
'!';
417 const char *la = cursor - negate;
426 char right_buffer[strlen(cursor)+1];
427 const char *right = right_buffer;
429 while (cursor && !condition) {
431 const char *kom = strchr(cursor,
',');
432 const char *next = kom;
440 int len = kom-cursor+1;
441 memcpy(right_buffer, cursor, len);
442 right_buffer[len] = 0;
449 case '=': condition = strcmp(left, right) == 0;
break;
450 case '~': condition = strstr(left, right) !=
NULp;
break;
451 case '<': condition = atoi(left) < atoi(right);
break;
459 if (negate) condition = !condition;
467 if (!err && !condition) jump(
at()->ELSE->
next);
495 int Interpreter::do_push() {
513 void Interpreter::pop() {
526 int Interpreter::do_pop() {
535 int Interpreter::do_gosub(
const char *str) {
537 if (do_push() == 0) {
557 const Code *fun = find_fun(fun_name);
565 const char *fpara = fpara_eval;
567 if (!*fpara) fpara =
NULp;
570 const char *nfpara =
NULp;
572 int err = eval_failed;
573 for (
char *para = params; !err && para; para=npara, fpara=nfpara) {
610 const char *s = read_var(fpara_name);
612 print_error(fun,
formatted(
"duplicated formal parameter '%s' in definition of function '%s'", fpara_name, fun_name));
616 write_var(fpara_name, para_eval);
630 if (!err) jump(fun->
next);
640 int Interpreter::do_goto(
const char *str) {
641 const Code *func = find_fun(str);
650 int Interpreter::do_return() {
655 int Interpreter::do_for(
const char *str) {
659 const char *eq = strchr(str,
'=');
664 const char *to = strstr(eq,
"TO");
665 if (!to)
print_error(
at(),
"TO not found in FOR - expecting e.g. 'FOR $(i) = a TO b'");
682 printf_error(
at(),
"Undefined Ident '%s' in FOR (use CREATE first)", ident);
686 fd.
forstr = strdup(ident);
693 const char *p = strrchr(ident,
'/');
700 fd.
forstr = strdup(p ? p+1 : ident);
713 int Interpreter::do_next() {
759 virtual bool matches(
const char *code)
const = 0;
763 return Interpreter::instance->
at()->
source;
776 mutable int dispatched;
780 if (dispatched>DISPATCH_LIMIT) {
786 if (res) fprintf(stderr,
"[result=%i]", res);
788 if (evaluated_args) {
790 fputs(evaluated_args, stderr);
795 free(evaluated_args);
799 NamedCommand(
const char *cmd) : name(cmd), len(strlen(name)), dispatched(0) {}
800 bool matches(
const char *code)
const OVERRIDE {
return strncmp(code, name, len) == 0; }
829 : expr.evaluate(failed);
841 char *args = eval(interpret, eval_failed);
842 if (args && !eval_failed) {
843 char *trimmed = args;
846 res = (interpret.*fun)(trimmed);
857 void Interpreter::command_table_setup(
bool setup) {
859 command_table =
new Command*[MAX_COMMANDS+1];
863 command_table[i++] =
new ArgCommand(
"MOVETO", &Interpreter::do_moveto, EVAL_VAR_DECL);
864 command_table[i++] =
new ArgCommand(
"SET", &Interpreter::do_set, EVAL_VAR_DECL);
865 command_table[i++] =
new ArgCommand(
"CONST", &Interpreter::do_makeconst, EVAL_VAR_DECL);
866 command_table[i++] =
new ArgCommand(
"CREATE", &Interpreter::do_create, EVAL_VAR_DECL);
868 command_table[i++] =
new ArgCommand(
"PRINT", &Interpreter::do_write_current, EVAL_PLAIN);
869 command_table[i++] =
new ArgCommand(
"P ", &Interpreter::do_write_current, EVAL_PLAIN);
870 command_table[i++] =
new ArgCommand(
"PP", &Interpreter::do_write_stdout);
871 command_table[i++] =
new SimpleCmmd(
"--", &Interpreter::do_newline);
872 command_table[i++] =
new SimpleCmmd(
"PMSTART", &Interpreter::do_write_maybe_start);
873 command_table[i++] =
new SimpleCmmd(
"PMEND", &Interpreter::do_write_maybe_end);
874 command_table[i++] =
new ArgCommand(
"PM", &Interpreter::do_write_maybe);
876 command_table[i++] =
new ArgCommand(
"GOSUB", &Interpreter::do_gosub, DONT_EVAL);
877 command_table[i++] =
new ArgCommand(
"CALL", &Interpreter::do_gosub, DONT_EVAL);
878 command_table[i++] =
new ArgCommand(
"GOTO", &Interpreter::do_goto);
879 command_table[i++] =
new SimpleCmmd(
"RETURN", &Interpreter::do_return);
880 command_table[i++] =
new SimpleCmmd(
"PUSH", &Interpreter::do_push);
881 command_table[i++] =
new SimpleCmmd(
"POP", &Interpreter::do_pop);
882 command_table[i++] =
new SimpleCmmd(
"CONTINUE", &Interpreter::do_next);
885 command_table[i++] =
new ArgCommand(
"CLOSE", &Interpreter::do_close);
888 command_table[i++] =
new ArgCommand(
"INDENT", &Interpreter::do_indent);
889 command_table[i++] =
new ArgCommand(
"TABSTOP", &Interpreter::do_tabstop);
890 command_table[i++] =
new ArgCommand(
"TAB", &Interpreter::do_tab);
891 command_table[i++] =
new SimpleCmmd(
"EXIT", &Interpreter::do_exit);
894 command_table[i++] =
new ArgCommand(
"DUMPDATA", &Interpreter::do_dumpdata,
TERMINATED_ON_ERROR);
896 command_table[i++] =
new ArgCommand(
"WARNING", &Interpreter::do_warning);
899 command_table[i++] =
NULp;
904 for (
int i = 0; command_table[i]; ++i)
delete command_table[i];
905 delete [] command_table;
909 const Command *Interpreter::find_command(
const Code *co) {
910 for (
int c = 0; command_table[c]; ++c) {
911 const Command& cmd = *command_table[c];
920 int Interpreter::run_program() {
923 for (pc = prg; pc; pc = nextpc) {
930 char *val = expr.evaluate(eval_failed);
931 int err = eval_failed;
932 if (!err) err = do_if(val);
946 char *val = expr.evalVarDecl(eval_failed);
947 bool abort = !val || eval_failed || do_for(val);
954 if (do_next())
return 1;
959 print_error(
at(),
"fatal: ran into FUNCTION (missing EXIT?)");
965 int res = pc->
cmd->
call(*
this);
966 if (res == -1)
return 1;
void set_cursor(const Token *newCursor)
int(Interpreter::* NoArgFun)()
char * copy_string_part(const char *first, const char *last)
virtual int check_result(int res, char *evaluated_args) const
const char * get_path() const
AliDataPtr format(AliDataPtr data, const size_t wanted_len, GB_ERROR &error)
ArgParser(const char *arguments, const Code *co)
for_data & add_for_data_to(const Code *co)
bool matches(const char *) const
CONSTEXPR_INLINE bool is_SEP_LF_EOS(char c)
static char errbuf[ERRBUF_SIZE]
static const Interpreter * instance
const char * formatted(const char *format,...)
void write(const char *key, const char *val)
int write(const char *val) __ATTR__USERESULT
const Token * get_cursor() const
bool matches(const char *code) const OVERRIDE
char buffer[MESSAGE_BUFFERSIZE]
ArgCommand(const char *cmd, ArgFun fun_, CallMode emode_=STANDARD_CALL)
static HelixNrInfo * start
NamedCommand(const char *cmd)
void remove_for_data_from(const Code *co)
static int diff(int v1, int v2, int v3, int v4, int st, int en)
static int get_error_count()
const Token * find_token(const Token *curs, const char *str, LookupScope scope) const
var_ref get_local(const char *key)
#define print_error(code_or_loc, err)
const TokenList * next_list() const
const TokenList * first_list() const
int call(Interpreter &interpret) const OVERRIDE
static void announce_exit_pc(const Location &exitingHere)
ArgParser(const char *arguments, const Location &loc_)
SimpleCmmd(const char *cmd, NoArgFun fun_)
char * evalVarDecl(bool &failed)
vfprintf(stderr, format, parg)
CONSTEXPR_INLINE bool is_SPACE_SEP_LF_EOS(char c)
static const Location & guess_pc()
char * get_ident(const char *&code, const Code *at)
int call(Interpreter &interpret) const OVERRIDE
virtual bool matches(const char *code) const =0
const Token * next_token() const
const char * read(const char *key) const
void SKIP_SPACE_LF_BACKWARD(const char *&var, const char *strStart)
fputs(TRACE_PREFIX, stderr)
char * evaluate(bool &failed)
void set_source(const Location &other)
const Data & get_data() const
#define printf_error(code_or_loc, format, arg)
virtual int call(Interpreter &interpret) const =0
int(Interpreter::* ArgFun)(const char *)
void start_message(const char *prefix) const
const TokenListBlock * get_tokens() const
void dump_cursor_pos(FILE *out) const
#define aisc_assert(cond)
static void write_aisc(const TokenListBlock *block, FILE *out, int indentation)
void print_tabs(int count, FILE *out)
void SKIP_SPACE_LF(const char *&var)
const Token * find_qualified_token(const char *str, LookupScope scope) const
const Location & pc() const
GB_write_int const char s