/* Do not remove the headers from this file! see /USAGE for more info. */ inherit M_ACCESS; private mapping inheritable = ([ "accountant" : ACCOUNTANT, "aggressive" : AGGRESSIVE_MONSTER, "following monster" : FOLLOWING_MONSTER, "monster" : ADVERSARY, "living" : LIVING, "wandering monster" : WANDERING_MONSTER, "armor" : ARMOR, "book" : BOOK, "container" : CONTAINER, "key" : KEY, "moving room" : "/std/moving_room", "object" : OBJ, "outdoor" : OUTDOOR_ROOM, "portal" : PORTAL, "room" : ROOM, "door" : DOOR, "hidden door" : HIDDEN_DOOR, "secret door" : SECRET_DOOR, "torch" : TORCH, "weapon" : WEAPON, "actor": M_ACTIONS, "block" : M_BLOCKEXITS, "drinkable" : M_DRINKABLE, "gettable" : M_GETTABLE, "lockable" : M_LOCKABLE, "openable" : M_OPENABLE, "readable" : M_READABLE, "regex" : M_REGEX, "valuable" : M_VALUABLE, "vendor" : M_VENDOR, ]); int cur, intrigger; int unique; string handle_oneof(string arg, array block); string handle_expression(string arg); mixed handle_subexpression(string arg); string handle_block(array lines); string handle_check(string arg, array block); string handle_delay(string arg); string handle_action(string arg); void add_error(int, string); private mapping keywords = ([ "oneof" : (: handle_oneof :), "if" : (: "if (" + handle_expression($1) + ") {\n" + handle_block($2) + "}\n" :), "nexttrigger" : (: intrigger ? "continue;" : (add_error(cur, "nexttrigger illegal outside of trigger"), "") :), "call" : (: handle_expression("call " + $1) +";\n" :), "lcall" : (: handle_expression("lcall " + $1) +";\n" :), "check" : (: handle_check :), "ok" : "return 1;", "write" : (: "write(" + handle_expression($1) + ");\n" :), "lpc" : (: implode($2, "\n") + "\n" :), "delay" : (: handle_delay :), "action" : (: handle_action :), "return" : (: "return " + handle_expression($1) + ";\n" :), ]); mixed handle_periodic(string arg, array lines); mixed handle_trigger(string arg, array lines); mixed handle_setup(string arg, array lines); private mapping funcs = ([ "periodic" : (: handle_periodic :), "trigger" : (: handle_trigger :), "setup" : (: handle_setup :), ]); string handle_string(array args); mixed handle_is(array args); mixed handle_variables(array args); mixed handle_gender(array args); mixed handle_list(string s1, string s2, array args); mixed handle_objects(array args); mixed handle_exits(array args); mapping attributes; int dest, indent, linesync; array lines; array errors; string fname, tail; string setup_args; array cur_vars; array globals; array inherits; array triggers; void create() { set_privilege(1); } void add_error(int line, string err) { if (sizeof(errors) < 3) errors += ({ fname + ":" + line + "-> " + err }); } void do_errors() { if (sizeof(errors)) error("Script compilation failed:\n" + implode(errors, "\n") + "\n"); } array line_info() { if (linesync) { linesync = 0; return ({ cur }); } return ({}); } array parse_long_string() { int first = cur; string ind; int indent; string firstline; if (cur == sizeof(lines)) return ({}); firstline = lines[cur++]; while (firstline[indent] == ' ') indent++; if (indent == 0) add_error(cur, "Bad indentation."); ind = repeat_string(" ", indent); while (cur < sizeof(lines)) { string line = lines[cur++]; if (line[0..indent-1] != ind) { if (line != "end") add_error(cur, "Missing end."); break; } } return map(lines[first..cur-2], (: $1[$(indent)..] :)); } array parse_block(int oldind, int indent) { int needend = -1; array ret = ({}); while (cur < sizeof(lines)) { int newind; string line = lines[cur++]; if (line == "" || line[0] == '#') { linesync = 1; continue; } if (line[0] == ' ') { newind = 1; while (line[newind] == ' ') newind++; line = line[newind..]; } else newind = 0; if (indent == -1) { if (newind == 0) add_error(cur, "Bad indentation."); indent = newind; } if (newind < indent) { if (line == "end") { if (newind == oldind) { needend = 0; break; } else if (needend) add_error(cur, "Bad indentation for 'end'."); } cur--; break; } else if (newind > indent) { if (arrayp(ret[<1])) add_error(cur, "Bad indentation."); cur--; ret[<1] = ({ ret[<1] }) + line_info() + parse_block(indent, newind); } else { ret += line_info() + ({ line }); needend++; } } if (needend > 0) add_error(cur-1, "Missing 'end'."); return ret; } void assert_alphanum(int line, string what) { if (!regexp(what, "^[A-Za-z][A-Za-z0-9_]*$")) add_error(line, "Illegal name '" + what + "'."); } void handle_grouping() { int newind; attributes = ([ "is" : ({ LPSCRIPT_SPECIAL, (: handle_is :) }), "variables" : ({ LPSCRIPT_SPECIAL, (: handle_variables :) }) ]); unique = linesync = cur = dest = indent = 0; tail = setup_args = ""; cur_vars = globals = ({}); while (cur < sizeof(lines)) { mixed part1; string part2, part3; string line = lines[cur++]; if (line == "" || line[0] == '#') { linesync = 1; continue; } if (line[0] == ' ') add_error(cur, "Bad indentation."); if (sscanf(line, "%s[%s]=%s", part1, part2, part3) == 3) { assert_alphanum(cur, part1); part1 = ({ "=[", part1, part2 }); part2 = part3; } else if (sscanf(line, "%s[%s]:%s", part1, part2, part3) == 3) { assert_alphanum(cur, part1); part1 = ({ ":[", part1, part2 }); part2 = part3; } else if (sscanf(line, "%s=%s", part1, part2) == 2) { assert_alphanum(cur, part1); part1 = ({ "=", part1 }); } else if (sscanf(line, "%s:%s", part1, part2) == 2) { assert_alphanum(cur, part1); part1 = ({ ":", part1 }); } else if (line == "---") { tail = implode(lines[cur..], "\n"); lines = lines[0..dest-1]; return; } else part1 = 0; if (part1) { if (part2 == "") { if (part1[0][0] == "=") lines[dest++] = line_info() + part1 + parse_long_string(); else { lines[dest++] = line_info() + part1 + parse_block(0, -1); } } else { if (part1[0][0] == ":") add_error(cur, "Illegal function declaration"); lines[dest++] = line_info() + part1 + ({ trim_spaces(part2) }); } } else add_error(cur, "Syntax error"); } lines = lines[0..dest-1]; } /* * expr1 ::= <number> * expr1 ::= <literal> * expr1 ::= '(' subexp ')' * expr1 ::= '$' var */ mixed handle_expr1(string arg) { string rest = ""; mixed tmp; switch (arg[0]) { case '(': tmp = handle_subexpression(arg[1..]); if (tmp[1][0] != ')') add_error(cur, "expected ')'"); return ({ tmp[0], trim_spaces(tmp[1][1..]) }); case '0'..'9': if (sscanf(arg, "%d%s", tmp, rest) == 2) return ({ tmp+"", trim_spaces(rest) }); break; case '$': sscanf(arg, "$%([A-Za-z0-9_]*)%s", arg, rest); if (member_array(arg, cur_vars) == -1) add_error(cur, "Undefined variable '" + arg + "'"); rest = trim_spaces(rest); return ({ "_" + arg, rest }); case '"': if (sscanf(arg, "\"%(([^\\\"]|\\.)*)\"%s", tmp, rest) != 2) add_error(cur, "Missing '\"'"); return ({ "\"" + tmp + "\"", trim_spaces(rest) }); case 'A'..'Z': case 'a'..'z': sscanf(arg, "%([A-Za-z]*)%s", arg, rest); rest = trim_spaces(rest); switch (arg) { case "who": return ({ "this_body()", rest }); case "me": return ({ "this_object()", rest }); case "here": return ({ "environment(this_body())", rest }); case "container": return ({ "environment(this_object())", rest }); case "chance": tmp = handle_expr1(rest); return ({ "random(100) < " + tmp[0], tmp[1] }); } } add_error(cur, "'" + arg + "' unrecognized."); return ({ "", rest }); } string handle_call(string s1, string s2, array rest...) { return "call_other(" + s1 + ", " + s2 + (sizeof(rest) > 0 ? "," : "") + implode(rest, ", ") + ")"; } string handle_lcall(string s1, array rest...) { if (s1[0] == '"' && s1[<1] == '"') return s1[1..<2] + "(" + implode(rest, ", ") + ")"; else return handle_call("this_object()", s1, rest...); } mixed handle_prefix(string arg) { string rest = ""; sscanf(arg, "%s %s", arg, rest); rest = trim_spaces(rest); switch (arg) { case "find": return ({ (: "present(" + $1 + ", " + $2 + ")" :), rest, 2 }); case "call": return ({ (: handle_call :), rest, -3 }); case "lcall": return ({ (: handle_lcall :), rest, -1 }); case "not": return ({ (: "!" + $1 :), rest, 1 }); case "new": return ({ (: "new(" + $1 + ")" :), rest, 1 }); } return 0; } mixed handle_infix(string arg) { string rest = ""; sscanf(arg, "%s %s", arg, rest); rest = trim_spaces(rest); switch (arg) { case "notequal": return ({ (: $1 + " != " + $2 :), rest }); case "<": case ">": case "<=": case ">=": case "!=": case "==": return ({ (: $1 + " " + $(arg) + " " + $2 :), rest }); } return 0; } mixed handle_assignment(string arg) { string var; string rest; mixed tmp; sscanf(arg, "%([A-Za-z0-9_]*)%s", var, rest); rest = trim_spaces(rest); if (rest[0] != '=') add_error(cur, "Expected '=' after '$" + var + "'"); else rest = rest[1..]; if (var == "") add_error(cur, "Missing variable name after '$'"); tmp = handle_expression(rest); if (member_array(var, cur_vars) == -1) { cur_vars += ({ var }); return ({ "_" + var + "=" + tmp, "_" + var }); } else { return ({ "_" + var + "=" + tmp, 0 }); } } /* * expr2 ::= expr1 * expr2 ::= PREFIX expr2 * expr2 ::= PREFIX2 expr2 expr2 */ mixed handle_expr2(string arg) { int grabextra; string rest; mixed tmp; function f; int num; array args = ({}); if (arg == "") { add_error(cur, "expression expected."); return ({ "0", "" }); } else if (tmp = handle_prefix(arg)) { num = tmp[2]; rest = tmp[1]; f = tmp[0]; if (num < 0) { grabextra = 1; num = -(num + 1); } while (num-- > 0) { tmp = handle_expr2(rest); args += ({ tmp[0] }); rest = tmp[1]; } if (grabextra) { while (rest != "" && rest[0] != ')') { tmp = handle_expr2(rest); args += ({ tmp[0] }); rest = tmp[1]; } } tmp[0] = evaluate(f, args...); tmp[1] = rest; return tmp; } else return handle_expr1(arg); } /* * subexp ::= expr2 INFIX subexp */ mixed handle_subexpression(string arg) { mixed tmp, tmp2, tmp3; if (arg == "") { add_error(cur, "expression expected."); return ({ "0", "" }); } else { tmp = handle_expr2(arg); if (tmp2 = handle_infix(tmp[1])) { tmp3 = handle_subexpression(tmp2[1]); tmp[0] = evaluate(tmp2[0], tmp[0], tmp3[0]); tmp[1] = tmp3[1]; } return tmp; } } string handle_expression(string arg) { mixed tmp; tmp = handle_subexpression(trim_spaces(arg)); if (tmp[1] != "") add_error(cur, "junk found after valid expression"); return tmp[0]; } string translate_string(string str) { string before, var; string ret = "\""; str = replace_string(str, "\"", "\\\""); while (sscanf(str, "%s$%s", before, str) == 2) { ret += before; sscanf(str, "%([A-Za-z0-9_]*)%s", var, str); ret += "\" + _" + var + " + \""; } ret += str + "\""; return ret; } string handle_block(array lines) { array ret = ({ "", "" }); int i; string tmp; foreach (mixed line in lines) { if (intp(line)) { cur = line; } else if (arrayp(line)) { string keyword, args; function f; keyword = line[0]; sscanf(keyword, "%s %s", keyword, args); if (f = keywords[keyword]) { ret[<2] += evaluate(f, args, line[1..]); } else add_error(cur, "Unknown keyword '" + keyword + "'."); } else if (line[0] == '!') { if (member_array(M_ACTIONS, inherits) != -1) ret[<2] += "respond(" + translate_string(line[1..]) + ");\n"; else ret[<2] += "this_object()->do_game_command(" + translate_string(line[1..]) + ");\n"; } else if (line[0] == '$') { mixed tmp2; tmp2 = handle_assignment(line[1..]); if (tmp2[1]) ret[<1] += "mixed " + tmp2[1] + ";\n"; ret[<2] += tmp2[0] + ";\n"; } else { string keyword, args; function f; keyword = line; sscanf(keyword, "%s %s", keyword, args); if (f = keywords[keyword]) { ret[<2] += evaluate(f, args, ({})); } else add_error(cur, "Unknown keyword '" + keyword + "'."); if (keyword == "delay") ret += ({ "", "" }); } } tmp = ""; for (i = 0; i < sizeof(ret); i += 2) tmp += "{\n" + ret[i+1] + ret[i] + ";\n}\n"; return tmp; } string handle_action(string arg) { if (member_array(M_ACTIONS, inherits) != -1) return "simple_action(\"" + arg + "\", this_object());"; else return "this_body()->simple_action(\"" + arg + "\", this_object());"; } string sub_file_name() { array tmp = split_path(fname); return tmp[0] + "tmp_" + tmp[1][0..<5] + "_" + (unique++) + ".scr"; } string handle_delay(string arg) { int idx = unique++; string args, rest; array locals = cur_vars - globals; if (intrigger) add_error(cur, "Delay illegal inside trigger (move to a function).\n"); if (sizeof(locals)) { args = "mixed _" + implode(locals, ", mixed _"); rest = ", _" + implode(locals, ", _"); } else args = rest = ""; return "call_out(\"unnamed" + idx + "\", " + arg + rest + "); }\n}\n\nvoid unnamed" + idx + "(" + args + ") {\n{\n"; } string handle_check(string arg, array lines) { string ret = ""; foreach (string line in lines) { string left = "", right = ""; string tmpl, tmpr; if (sscanf(line, "%s:%s", left, right) != 2) add_error(cur, "Missing ':'"); tmpl = handle_expression(left); tmpr = handle_expression(right); ret += "if (" + tmpl + ")\n return " + tmpr + ";\n"; } ret += "return 1;"; return ret; } string handle_oneof(string arg, array block) { string ret; ret = "switch (random(" + sizeof(block) + ")) {\n"; for (int i = 0; i < sizeof(block); i++) { ret += "case " + i + ": {\n"; ret += handle_block( ({ block[i] }) ); ret += "break; }\n"; } return ret + "}\n"; } mixed handle_periodic(string arg, array lines) { int min, max; string time; if (sscanf(arg, "%d to %d", min, max) == 2) { time = min + " + random(" + (max-min) + ")"; } else { sscanf(arg, "%d", min); time = "" + (min || 2); } cur_vars = globals; return ({ "setup", "f = function(function f) { " + handle_block(lines) + " call_out(f, " + time + ", f); }; call_out(f, " + time + ", f)" }); } mixed handle_setup(string arg, array lines) { setup_args = arg; cur_vars = globals; return ({ "setup", handle_block(lines) }); } mixed handle_trigger(string arg, array lines) { int num; int oldlen; intrigger = 1; oldlen = strlen(arg); arg = replace_string(arg, "*", "%s"); num = strlen(arg) - oldlen; cur_vars = globals; triggers += ({ ({ arg, num, handle_block(lines) }) }); intrigger = 0; return 0; } varargs string regenerate(array lines, int level) { string ind = repeat_string(" ", level); string ret = ""; foreach (mixed item in lines) { if (intp(item)) continue; if (arrayp(item)) { ret += ind + item[0] + "\n" + regenerate(item[1..], level + 1) + ind + "end\n"; } else ret += ind + item + "\n"; } return ret; } // This allows certain attributes which should represent a single object // (eg wielded = weapon) to optionally accept a random choice : // wielded = // weapon1 // weapon2 // end string one_object(array args) { string array output = ({}); foreach (mixed line in args) { if (arrayp(line)) { string fn = sub_file_name(); string id, rest; object ob; if (sscanf(line[0], "%s=%s", id, rest) != 2 || id == "" || rest != "") add_error(cur, "Syntax error in subobject.\n"); unguarded(1, (: write_file, fn, regenerate(line[1..]), 1 :)); if (ob = find_object(fn)) destruct(ob); // we want it to recompile too line = fn; } output += ({ sprintf(" \"%s\" ", line) }); } if(sizeof(output)>1) return "choice( ({" + implode(output, ", ") + "}) )"; else return output[0]; } mixed handle_wield(array args) { return ({ "setup", "set_wielding(" + one_object(args) + ")" }); } mixed handle_wear(array args) { return ({ "setup", "set_wearing(" + one_object(args) + ")" }); } mixed handle_objects(array args) { string ret = "set_objects( ([\n"; string tmp; foreach (mixed line in args) { if (arrayp(line)) { string fn = sub_file_name(); string id, rest; object ob; if (sscanf(line[0], "%s=%s", id, rest) != 2 || id == "" || rest != "") add_error(cur, "Syntax error in subobject.\n"); unguarded(1, (: write_file, fn, regenerate(line[1..]), 1 :)); if (ob = find_object(fn)) destruct(ob); // we want it to recompile too line = fn; } if (sscanf(line, "%s(%s", line, tmp) == 2) { if (tmp[<1] == ')') tmp = tmp[0..<2]; ret += sprintf(" \"%s\" : ({ %s }),\n", line, tmp); } else { ret += sprintf(" \"%s\" : 1,\n", line); } } return ({ "setup", ret + "]) )" }); } mixed handle_mapping(string rfunc, string func, array args) { string ret = func + "( ([\n"; foreach (string line in args) { string exit, value; if (sscanf(line, "%s:%s", exit, value) != 2) { add_error(cur, "Illegal exit value"); continue; } exit = trim_spaces(exit); value = trim_spaces(value); ret += sprintf(" \"%s\" : \"%s\",\n", exit, value); } return ({ rfunc, ret + "]) )" }); } mixed handle_int_mapping(string rfunc, string func, array args) { string ret = func + "( ([\n"; foreach (string line in args) { string key, value; if (sscanf(line, "%s:%s", key, value) != 2) { add_error(cur, "Illegal int map value"); continue; } key = trim_spaces(key); value = trim_spaces(value); ret += sprintf(" \"%s\" : %s,\n", key, value); } return ({ rfunc, ret + "]) )" }); } string handle_string(array args) { string ret = implode(map(args, (: stringp($1) ? $1 : "%-%" :)), ""); int ret_size; ret = replace_string(ret, " %-% ", "\n\n"); ret = replace_string(ret, "%-%", ""); ret = replace_string(ret, "\"", "\\\""); ret_size = sizeof(ret); if (ret_size > 65) { string tmp = ""; for (int i = 0; i <= ret_size; i += 65) { int j; if (i+64 >= ret_size) j = ret_size - 1; else j = i+64; tmp += "\"" + ret[i..j] + "\"\n"; } return tmp; } return "\"" + ret + "\""; } mixed handle_flags(array args) { string ret = "0"; args = map(explode(args[0], ","), (: trim_spaces :)); foreach (string arg in args) { switch (arg) { case "attached" : ret += " | ATTACHED"; break; } } return ({ "setup", "set_flag(" + ret + ")" }); } mixed handle_list(string rfunc, string func, array args) { args = map(explode(args[0], ","), (: trim_spaces :)); return ({ rfunc, func + "(\"" + implode(args, "\", \"") + "\")" }); } void get_attributes(string fname) { object ob = load_object(fname); mapping tmp; if (!ob) return; foreach (string prog in deep_inherit_list(ob)) { tmp = prog->lpscript_attributes(); if (tmp) attributes += tmp; } tmp = ob->lpscript_attributes(); if (tmp) attributes += tmp; } mixed handle_variables(array args) { args = map(explode(args[0], ","), (: trim_spaces :)); globals += args; return ({ -1, "mixed _" + implode(args, ";\nmixed _") }); } mixed handle_is(array args) { args = map(explode(args[0], ","), (: trim_spaces :)); foreach (string file in args) { if (file[0] == '"' && file[<1] == '"') { get_attributes(file); inherits += ({ file }); } else if (inheritable[file]) { get_attributes(inheritable[file]); inherits += ({ inheritable[file] }); } else add_error(cur, "'" + file + "' unknown."); } return 0; } mixed handle_gender(array args) { int gen; switch (args[0]) { case "male": gen = 1; break; case "female": gen = 2; break; case "neuter": gen = 0; break; } return ({ "setup", "set_gender(" + gen + ")" }); } int handle_boolean(string arg) { switch (arg) { case "true": return 1; break; case "false": return 0; break; } } array handle_attribute(mixed entry, array args) { switch (entry[0]) { case LPSCRIPT_LIST: return handle_list(entry[1], entry[2], args); case LPSCRIPT_STRING: return ({ entry[1], entry[2] + "(" + handle_string(args) + ")" }); case LPSCRIPT_INT: return ({ entry[1], entry[2] + "(" + args[0] + ")" }); case LPSCRIPT_OBJECTS: return handle_objects(args); case LPSCRIPT_WIELD: return handle_wield(args); case LPSCRIPT_WEAR: return handle_wear(args); case LPSCRIPT_GENDER: return handle_gender(args); case LPSCRIPT_BOOLEAN: return ({ entry[1], entry[2] + "(" + handle_boolean (args[0]) + ")" }); case LPSCRIPT_MAPPING: return handle_mapping(entry[1], entry[2], args); case LPSCRIPT_INT_MAPPING: return handle_int_mapping(entry[1], entry[2], args); case LPSCRIPT_SPECIAL: return evaluate(entry[1], args); case LPSCRIPT_FLAGS: return handle_flags(args); case LPSCRIPT_TWO: return evaluate(entry[1], args[0], args[1..]); } return 0; } void handle_parsing() { cur = 0; inherits = ({}); triggers = ({}); for (int i = 0; i < sizeof(lines); i++) { int j; mixed arr = lines[i]; mixed entry; if (intp(arr[0])) { cur = arr[0]; j = 1; } else j = 0; switch (arr[j]) { case "=": if (entry = attributes[arr[j+1]]) { cur++; lines[i] = handle_attribute(entry, arr[j+2..]); } else add_error(cur++, "Unknown attribute '" + arr[j+1] + "'."); break; case "=[": if (entry = attributes[arr[j+1]]) { cur++; lines[i] = handle_attribute(entry, arr[j+2..]); } else add_error(cur++, "Unknown attribute '" + arr[j+1] + "'."); break; case ":": cur_vars = globals; lines[i] = ({ arr[j+1], handle_block(arr[j+2..]) }); break; case ":[": if (entry = funcs[arr[j+1]]) { cur++; lines[i] = evaluate(entry, arr[j+2], arr[j+3..]); } else add_error(cur++, "Unknown function '" + arr[j+1] + "'."); break; default: error("Internal error.\n"); } } } private nomask void handle_generation(string outname) { string header = implode(inherits, (: $1 + "inherit \"" + $2 + "\";\n" :), "") + "\n"; string ret = ""; string globals = ""; string protos = ""; array tmp; string actions = ""; if (sizeof(triggers)) { for (int i = 0; i < sizeof(triggers); i++) actions += "case " + i + ":\n" + triggers[i][2] + "return;\n"; ret += "array patterns = ({ "; for (int i = 0; i < sizeof(triggers); i++) { if (i) ret += ", "; ret += "\"" + triggers[i][0] + "\""; } ret += "});\n"; ret += "array num = ({ "; for (int i = 0; i < sizeof(triggers); i++) { if (i) ret += ", "; ret += triggers[i][1]; } ret += "});\n"; /*******************************/ ret += @END void receive_outside_msg(string str) { string _1, _2, _3, _4, _5, _6; if (str[<1] == '\n') str = str[0..<2]; for (int i = 0; i < sizeof(patterns); i++) { if (sscanf(str, patterns[i], _1, _2, _3, _4, _5, _6) == num[i]) { switch (i) { END + actions + "}}}}"; /*******************************/ } tmp = unique_array(lines - ({ 0 }), (: $1[0] :)); foreach (array item in tmp) { if (item[0][0] == -1) { foreach (array block in item) globals += block[1] + ";\n"; continue; } else if (item[0][0] == "setup") { protos += "void setup(" + setup_args + ");\n"; ret += "\nvoid setup(" + setup_args + ") {\nfunction f;\n"; } else { protos += "mixed " + item[0][0] + "();\n"; ret += "\nmixed " + item[0][0] + "() {\n"; } foreach (array block in item) ret += block[1] + ";\n"; ret += "}\n\n"; } unguarded(1, (: write_file, outname,"#pragma no_warnings\n" + header + globals + protos + tail + ret, 1 :)); } object compile(string scrname) { mixed tmp = split_path(scrname); mixed path = tmp[0]; mixed name = tmp[1][0..<5]; /* no .scr */ mixed outname = path + "tmp_" + name + ".c"; mixed text; fname = scrname; text = read_file(scrname); if (!text) return 0; lines = explode(text, "\n"); errors = ({}); handle_grouping(); do_errors(); handle_parsing(); do_errors(); handle_generation(outname); return load_object(outname); }