/*
* compiler.c [virtual object compiler]
* description: a generic object description language parser. This is meant
* to be the base object that other ODL compilers inherit from.
* history:
* 07/01/92 [huthar] - created
* 12/08/92 [wayfarer] - cleaned up, added // comment support
* multiple line variables, subgroups
* 12/09/92 [wayfarer] - bug fixing for items, objects, etc.
* 12/10/92 [wayfarer] - allowed a non-fixed base object to be used
*/
// history: this object comes from the Portals mudlib. It is a nice
// abstraction of the room description language originally done by Truilkan.
#undef DEBUG
#include <config.h>
#include <uid.h>
private static string opcode, error_string;
private static int line_done;
private static object target;
static string subgroup, filename;
#define YES 1
#define NO 0
void end_subgroup()
{
string fun;
if (subgroup)
{
fun = subgroup+"_done";
call_other (this_object(), fun);
}
}
string parse_line (string line)
{
string op, val;
int i;
if (!line || line[0] == '#' || line == "" || line[0..1] == "//")
return "";
if (sscanf(line, "%s: %s",op,val) == 2)
{
opcode = op;
line_done = YES;
}
else if (sscanf(line, "%s:",op) == 1)
{
opcode = op;
line_done = NO;
return "";
}
else
{
val = line;
if (line_done)
line_done = NO;
if (val[0..1] == "**" || val == "." || val == "---")
{
line_done = YES;
return "";
}
else if (val == "{")
{
if (!subgroup)
{
subgroup = opcode;
return "";
}
else
{
error_string = "Can't have multiply nested subgroups.";
return 0;
}
}
else if (val == "}")
{
if (subgroup)
{
end_subgroup();
subgroup = NO;
opcode = NO;
line_done = YES;
return "";
}
else
{
error_string = "End subgroup found when no subgroup started.";
return 0;
}
}
else
val += "\n";
}
for(i = 0; i < strlen(val); i++)
if(i != ' ' && i != '\t')
break;
if(i == strlen(val))
{
opcode = op;
line_done = NO;
return "";
}
return val[i .. -1];
}
void set_target(object ob)
{
target = ob;
ob->set_file_name (filename);
}
object query_target()
{
return target;
}
int make_target (string name)
{
object ob;
if (!name)
name = (string)this_object()->default_base_object();
if (name)
{
seteuid(creator_file(filename));
ob = new (name);
set_target(ob);
}
if (!target)
return 0;
export_uid(target);
return 1;
}
void error (string val)
{
write (val);
if (target)
target->remove();
}
object compile_object (string file)
{
string *lines;
string tmp, value, ret;
int i;
file = file + (string)this_object()->extension();
if (file_size(file) == -1)
{
write ("No such file or directory: "+ file + "\n");
return 0;
}
seteuid(ROOT_UID);
tmp = read_file("/"+file);
if(!tmp || tmp == "")
{
write ("File is empty: "+ file + "\n");
return 0;
}
lines = explode(tmp,"\n");
target = 0;
filename = file;
subgroup = NO;
error_string = 0;
for(i = 0; i < sizeof(lines); i++)
{
line_done = YES;
value = "";
tmp = parse_line(lines[i]);
if (tmp == 0)
{
error ("Error Compiling '"+filename+"': "+error_string+"\n");
return 0;
}
if ((tmp == "") && line_done)
continue;
value = tmp;
while (line_done == NO)
{
if (i >= (sizeof(lines)-1))
break;
value += parse_line(lines[++i]);
}
if(!opcode)
{
error("Error Compiling '"+filename+"': Opcode missing in line #"+i+"\n");
return 0;
}
if (subgroup)
opcode = subgroup + "_" + opcode;
#ifdef DEBUG
printf ("<final> %s = %s\n",opcode,value);
#endif
if (!target && opcode != "base_object")
{
if (!make_target(0))
{
error ("Error Compiling '"+filename+"': No base object defined.\n");
return 0;
}
}
switch(call_other(this_object(),opcode,value,target))
{
case 0:
write("Warning Compiling '"+filename+"': Unknown opcode '"+opcode+
"' in line #"+i+"\n");
break;
case 2: // Fatal Compile Error
error("Fatal compile error: " + filename + "\n");
return 0;
break;
}
}
if (function_exists("compilation_finished",this_object()) &&
!((int)this_object()->compilation_finished()))
return 0;
return target;
}
/*
* no shadowing of ODL compilers!
*/
int query_prevent_shadow ()
{
return 1;
}