diff --git a/bin/hilfe b/bin/hilfe index 6e5cb7e541503167fc72aa8f233e395bb51ce348..bbd44cc59dc430f3bdc6dfe704a7152f395ac126 100755 --- a/bin/hilfe +++ b/bin/hilfe @@ -1,563 +1,7 @@ #!/usr/local/bin/pike -/* Incremental Pike evaluator */ - -#include <simulate.h> -#include <stdio.h> -import Array; -#include <string.h> -#include <getopt.h> - -/* todo: - * return (void)1; will give me problems. - * strstr(string,string *) -> return first occurance of first string... - * inherit doesn't work - * preprocessor stuff - */ - -#!define catch(X) ((X),0) - -#pragma all_inline - -/* #define DEBUG */ - - -mapping variables=([]); -mapping constants=([]); -string *functions=({}); -string *function_names=({}); -mapping query_variables() { return variables; } -/* do nothing */ - -void my_write(mixed x) -{ - write(sprintf("%O",x)); -} - - -object eval(string f) -{ - string prog,file; - object o; - mixed err; - prog=("#pragma unpragma_strict_types\n#pragma all_inline\n"+ - "static mapping ___variables=___hilfe->query_variables();\n"+ - map(indices(constants),lambda(string f) - { return constants[f]&&sprintf("constant %s=%s;",f,constants[f]); })*"\n"+ - map(indices(variables),lambda(string f) - { return sprintf("mixed %s=___variables[\"%s\"];",f,f); })*"\n"+ - "\nmapping query_variables() { return ([\n"+ - map(indices(variables),lambda(string f) - { return sprintf(" \"%s\":%s,",f,f); })*"\n"+ - "\n ]);\n}\n"+ - functions*"\n"+ - "\n# 1\n"+ - f+"\n"); - -#ifdef DEBUG - write("program:"+prog); -#endif - program p; - if(err=catch(p=compile_string(prog))) - { -#ifdef DEBUG - write(describe_backtrace(err)); - write("Couldn't compile expression.\n"); -#endif - return 0; - } - if(err=catch(o=clone(p))) - { - trace(0); - write(describe_backtrace(err)); - return 0; - } - return o; -} - -mixed do_evaluate(string a, int show_result) -{ - mixed foo, c; - if(foo=eval(a)) - { - if(c=catch(a=sprintf("%O",foo->___Foo4711()))) - { - trace(0); - if(arrayp(c) && sizeof(c)==2 && arrayp(c[1])) - { - c[1]=c[1][sizeof(backtrace())..]; - write(describe_backtrace(c)); - }else{ - write(sprintf("Error in evalutation: %O\n",c)); - } - }else{ - if(show_result) - write("Result: "+a+"\n"); - else - write("Ok.\n"); - variables=foo->query_variables(); - } - } -} - -string input=""; - -string skipwhite(string f) -{ - while(sscanf(f,"%*[ \r\n\t]%s",f) && sscanf(f,"/*%*s*/%s",f)); - return f; -} - -int find_next_comma(string s) -{ - int e, p, q; - - for(e=0;e<strlen(s);e++) - { - switch(s[e]) - { - case '"': - for(e++;s[e]!='"';e++) - { - switch(s[e]) - { - case 0: return 0; - case '\\': e++; break; - } - } - break; - - case '{': - case '(': - case '[': - p++; - break; - - case ',': - if(!p) return e; - break; - - case '/': - if(s[e+1]=='*') - while(s[e-1..e]!="*/" && e<strlen(s)) e++; - break; - - case '}': - case ')': - case ']': - p--; - if(p<0) - { - write("Syntax errror.\n"); - input=""; - return 0; - } - break; - - } - } - return 0; -} - -string *get_name(string f) -{ - int e,d; - string rest; - - f=skipwhite(f); - if(sscanf(f,"*%s",f)) f=skipwhite(f); - sscanf(f,"%[a-zA-Z0-9_]%s",f,rest); - rest=skipwhite(rest); - return ({f,rest}); -} - -string first_word=0; -int pos=0; -int parenthese_level=0; -int in_comment=0; -int in_string=0; -int in_quote=0; -int eq_pos=-1; -int do_parse(); -mixed parse_function(string s); -mixed parse_statement(string s); - -void set_buffer(string s,int parsing) -{ - input=s; - first_word=0; - pos=-1; - parenthese_level=0; - in_comment=0; - in_quote=0; - in_string=0; - eq_pos=-1; - if(!parsing) do_parse(); -} - -void clean_buffer() { set_buffer("",0); } - -void add_buffer(string s) -{ - input+=s; - do_parse(); - input=skipwhite(input); -} - -void cut_buffer(int where) -{ - int old,new; - old=strlen(input); - input=skipwhite(input[where..old-1]); - new=strlen(input); - if(where>1) first_word=0; - pos-=old-new; if(pos<0) pos=0; - eq_pos-=old-new; if(eq_pos<0) eq_pos=-1; -#ifdef DEBUG - write("CUT input = "+my_write(input)+" pos="+pos+"\n"); -#endif -} - -void print_version() -{ - write(version()+ - " running Hilfe v1.7 (Incremental Pike Frontend)\n"); -} - - -int do_parse() -{ - string tmp; - if(pos<0) pos=0; - for(;pos<strlen(input);pos++) - { - if(in_quote) { in_quote=0; continue; } -// trace(99); - if(!first_word) - { - int d; - if(!strlen(input) && pos) - { - werror("Error in optimizer.\n"); - exit(1); - } - - d=input[pos]; - if(d==' ' && !pos) - { - cut_buffer(1); - continue; - } - if((d<'a' || d>'z') && (d<'A' || d>'Z') && (d<'0' || d>'9') && d!='_') - { - first_word=input[0..pos-1]; -#ifdef DEBUG - write("First = "+my_write(first_word)+" pos="+pos+"\n"); - write("input = "+my_write(input)+"\n"); -#endif - switch(first_word) - { - case "quit": - write("Exiting.\n"); - exit(0); - case ".": - clean_buffer(); - write("Input buffer flushed.\n"); - continue; - - case "new": - this_object()->__INIT(); - continue; - - case "dump": - sum_arrays(lambda(string var,mixed foo) - { - write(sprintf("%-15s:%s\n",var,sprintf("%O",foo))); - }, - indices(variables), - values(variables)); - cut_buffer(4); - continue; - - case "help": - print_version(); - write("Hilfe is a tool to evaluate Pike interactively and incrementally.\n" - "Any Pike function, expression or variable declaration can be entered\n" - "at the command line. There are also a few extra commands:\n" - " help - show this text\n" - " quit - exit this program\n" - " . - abort current input batch\n" - " dump - dump variables\n" - " new - clear all function and variables\n" - "See the Pike reference manual for more information.\n" - ); - cut_buffer(4); - continue; - - } - } - } - - switch(input[pos]) - { - case '\\': - in_quote=1; - break; - - case '=': - if(in_string || in_comment || parenthese_level || eq_pos!=-1) break; - eq_pos=pos; - break; - - case '"': - if(in_comment) break; - in_string=!in_string; - break; - - case '{': - case '(': - case '[': - if(in_string || in_comment) break; - parenthese_level++; - break; - - case '}': - case ')': - case ']': - if(in_string || in_comment) break; - if(--parenthese_level<0) - { - write("Syntax error.\n"); - clean_buffer(); - return 0; - } - if(!parenthese_level && input[pos]=='}') - { - if(tmp=parse_function(input[0..pos])) - { - cut_buffer(pos+1); - if(stringp(tmp)) - set_buffer(tmp+input,1); - } - } - break; - - case ';': - if(in_string || in_comment || parenthese_level) break; - if(tmp=parse_statement(input[0..pos])) - { - cut_buffer(pos+1); - if(stringp(tmp)) - set_buffer(tmp+input,1); - } - break; - - case '*': - if(in_string || in_comment) break; - if(input[pos-1]=='/') in_comment=1; - break; - - case '/': - if(in_string) break; - if(input[pos-1]=='*') in_comment=0; - break; - } - } - if(pos>strlen(input)) pos=strlen(input); - return -1; -} - - -mixed parse_function(string fun) -{ - string name,a,b; - object foo; - mixed c; -#ifdef DEBUG - write("Parsing block ("+first_word+")\n"); -#endif - - switch(first_word) - { - case "if": - case "for": - case "do": - case "while": - case "foreach": - /* parse loop */ - do_evaluate("mixed ___Foo4711() { "+fun+" ; }\n",0); - return 1; - - case "int": - case "void": - case "object": - case "array": - case "mapping": - case "string": - case "multiset": - case "float": - case "mixed": - case "program": - case "function": - case "class": - /* parse function */ - if(eq_pos!=-1) break; /* it's a variable */ - sscanf(fun,first_word+"%s",name); - - c=get_name(name); - name=c[0]; - c=c[1]; - - int i; - if((i=member_array(name,function_names))!=-1) - { - b=functions[i]; - functions[i]=fun; - if(!eval("")) functions[i]=b; - }else{ - if(eval(fun)) - { - functions+=({fun}); - function_names+=({name}); - } - } - return 1; - } -} - -mixed parse_statement(string ex) -{ - string a,b,name; - mixed c; - object foo; - int e; -#ifdef DEBUG - write("Parsing statement ("+first_word+")\n"); -#endif - switch(first_word) - { - case "if": - case "for": - case "do": - case "while": - case "foreach": - /* parse loop */ - do_evaluate("mixed ___Foo4711() { "+ex+" ; }\n",0); - return 1; - - case "constant": - /* parse variable def. */ - sscanf(ex,first_word+"%s",b); - b=skipwhite(b); - c=get_name(b); - name=c[0]; - sscanf(c[1],"=%s",c[1]); - a=constants[name]; - constants[name]=c[1]; - if(!eval("")) constants[name]=a; - return 1; - - case "int": - case "void": - case "object": - case "array": - case "mapping": - case "string": - case "multiset": - case "float": - case "mixed": - case "program": - case "function": - /* parse variable def. */ - sscanf(ex,first_word+"%s",b); - b=skipwhite(b); - c=get_name(b); - name=c[0]; - c=c[1]; - -#ifdef DEBUG - write("Variable def.\n"); -#endif - if(name=="") - { - return 1; - }else{ - string f; - variables[name]=0; - - if(sscanf(c,"=%s",c)) - { -#ifdef DEBUG - write("Variable def. with assign. ("+name+")\n"); -#endif - if(e=find_next_comma(c)) - { - return name+"="+c[0..e-1]+";\n"+ - first_word+" "+c[e+1..strlen(c)-1]; - }else{ - return name+"="+c; - } -#ifdef DEBUG - write("Input buffer = '"+input+"'\n"); -#endif - - }else{ - sscanf(c,",%s",c); - return first_word+" "+c; - } - } - - return 1; - - default: - if(ex==";") return 1; - /* parse expressions */ - do_evaluate("mixed ___Foo4711() { return (mixed)("+ex[0..strlen(ex)-2]+"); }\n",1); - return 1; - } -} - -void stdin(string s) -{ - string *tmp,a,b,c,f,name; - int e,d; - object foo; - -#ifdef DEBUG - write("input: '"+my_write(s)+"'\n"); -#endif - s=skipwhite(s); - - if(s[0..1]==".\n") - { - clean_buffer(); - write("Input buffer flushed.\n"); - s=s[2..strlen(s)-1]; - } - add_buffer(s); -// if(!strlen(input)) write("> "); -} - -void signal_trap(int s) -{ - clean_buffer(); - throw("**Break\n"); -} - void main(int argc,string *argv) { - string s; - add_efun("write",my_write); - add_efun("___hilfe",this_object()); - - print_version(); - while(s=readline(strlen(input) ? ">> " : "> ")) - { - signal(signum("SIGINT"),signal_trap); - stdin(s+"\n"); - signal(signum("SIGINT")); - } - write("Terminal closed.\n"); - return 0; + Tools.Hilfe.StdinHilfe(); } diff --git a/lib/modules/Tools.pmod/Hilfe.pmod b/lib/modules/Tools.pmod/Hilfe.pmod new file mode 100644 index 0000000000000000000000000000000000000000..1dcae84d95a9a52013b95b57b8e52d38419edf0d --- /dev/null +++ b/lib/modules/Tools.pmod/Hilfe.pmod @@ -0,0 +1,635 @@ +class Evaluator +{ +/* Incremental Pike evaluator */ + +#include <simulate.h> +#include <stdio.h> +import Array; +#include <string.h> +#include <getopt.h> + +/* todo: + * return (void)1; will give me problems. + * strstr(string,string *) -> return first occurance of first string... + * inherit doesn't work + * preprocessor stuff + */ + +#!define catch(X) ((X),0) + +#pragma all_inline + +/* #define DEBUG */ + + mapping variables=([]); + mapping constants=([]); + string *functions=({}); + string *function_names=({}); + mapping query_variables() { return variables; } +/* do nothing */ + + function write; + + object eval(string f) + { + string prog,file; + object o; + mixed err; + prog=("#pragma unpragma_strict_types\n#pragma all_inline\n"+ + "function write;\n"+ + map(indices(constants),lambda(string f) + { return constants[f]&&sprintf("constant %s=%s;",f,constants[f]); })*"\n"+ + map(indices(variables),lambda(string f) + { return sprintf("mixed %s;",f,f); })*"\n"+ + "\nmapping query_variables() { return ([\n"+ + map(indices(variables),lambda(string f) + { return sprintf(" \"%s\":%s,",f,f); })*"\n"+ + "\n ]);\n}\n"+ + functions*"\n"+ + "\n# 1\n"+ + f+"\n"); + +#ifdef DEBUG + write("program:"+prog); +#endif + program p; + if(err=catch(p=compile_string(prog))) + { +#ifdef DEBUG + write(describe_backtrace(err)); + write("Couldn't compile expression.\n"); +#endif + return 0; + } + if(err=catch(o=clone(p))) + { + trace(0); + write(describe_backtrace(err)); + return 0; + } + foreach(indices(variables), string f) o[f]=variables[f]; + o->write=write; + return o; + } + + mixed do_evaluate(string a, int show_result) + { + mixed foo, c; + if(foo=eval(a)) + { + if(c=catch(a=sprintf("%O",foo->___Foo4711()))) + { + trace(0); + if(arrayp(c) && sizeof(c)==2 && arrayp(c[1])) + { + c[1]=c[1][sizeof(backtrace())..]; + write(describe_backtrace(c)); + }else{ + write(sprintf("Error in evalutation: %O\n",c)); + } + }else{ + if(show_result) + write("Result: "+a+"\n"); + else + write("Ok.\n"); + variables=foo->query_variables(); + } + } + } + + string input=""; + + string skipwhite(string f) + { + while(sscanf(f,"%*[ \r\n\t]%s",f) && sscanf(f,"/*%*s*/%s",f)); + return f; + } + + int find_next_comma(string s) + { + int e, p, q; + + for(e=0;e<strlen(s);e++) + { + switch(s[e]) + { + case '"': + for(e++;s[e]!='"';e++) + { + switch(s[e]) + { + case 0: return 0; + case '\\': e++; break; + } + } + break; + + case '{': + case '(': + case '[': + p++; + break; + + case ',': + if(!p) return e; + break; + + case '/': + if(s[e+1]=='*') + while(s[e-1..e]!="*/" && e<strlen(s)) e++; + break; + + case '}': + case ')': + case ']': + p--; + if(p<0) + { + write("Syntax errror.\n"); + input=""; + return 0; + } + break; + + } + } + return 0; + } + + string *get_name(string f) + { + int e,d; + string rest; + + f=skipwhite(f); + if(sscanf(f,"*%s",f)) f=skipwhite(f); + sscanf(f,"%[a-zA-Z0-9_]%s",f,rest); + rest=skipwhite(rest); + return ({f,rest}); + } + + string first_word=0; + int pos=0; + int parenthese_level=0; + int in_comment=0; + int in_string=0; + int in_quote=0; + int eq_pos=-1; + int do_parse(); + mixed parse_function(string s); + mixed parse_statement(string s); + + void set_buffer(string s,int parsing) + { + input=s; + first_word=0; + pos=-1; + parenthese_level=0; + in_comment=0; + in_quote=0; + in_string=0; + eq_pos=-1; + if(!parsing) do_parse(); + } + + void clean_buffer() { set_buffer("",0); } + + void add_buffer(string s) + { + input+=s; + do_parse(); + input=skipwhite(input); + } + + void cut_buffer(int where) + { + int old,new; + old=strlen(input); + input=skipwhite(input[where..old-1]); + new=strlen(input); + if(where>1) first_word=0; + pos-=old-new; if(pos<0) pos=0; + eq_pos-=old-new; if(eq_pos<0) eq_pos=-1; + } + + void print_version() + { + write(version()+ + " running Hilfe v2.0 (Incremental Pike Frontend)\n"); + } + + + int do_parse() + { + string tmp; + if(pos<0) pos=0; + for(;pos<strlen(input);pos++) + { + if(in_quote) { in_quote=0; continue; } +// trace(99); + if(!first_word) + { + int d; + if(!strlen(input) && pos) + { + werror("Error in optimizer.\n"); + exit(1); + } + + d=input[pos]; + if(d==' ' && !pos) + { + cut_buffer(1); + continue; + } + if((d<'a' || d>'z') && (d<'A' || d>'Z') && (d<'0' || d>'9') && d!='_') + { + first_word=input[0..pos-1]; +#ifdef DEBUG + write("First = "+first_word+" pos="+pos+"\n"); + write("input = "+input+"\n"); +#endif + switch(first_word) + { + case "quit": + write("Exiting.\n"); + exit(0); + case ".": + clean_buffer(); + write("Input buffer flushed.\n"); + continue; + + case "new": + this_object()->__INIT(); + continue; + + case "dump": + sum_arrays(lambda(string var,mixed foo) + { + write(sprintf("%-15s:%s\n",var,sprintf("%O",foo))); + }, + indices(variables), + values(variables)); + cut_buffer(4); + continue; + + case "help": + print_version(); + write("Hilfe is a tool to evaluate Pike interactively and incrementally.\n" + "Any Pike function, expression or variable declaration can be entered\n" + "at the command line. There are also a few extra commands:\n" + " help - show this text\n" + " quit - exit this program\n" + " . - abort current input batch\n" + " dump - dump variables\n" + " new - clear all function and variables\n" + "See the Pike reference manual for more information.\n" + ); + cut_buffer(4); + continue; + + } + } + } + + switch(input[pos]) + { + case '\\': + in_quote=1; + break; + + case '=': + if(in_string || in_comment || parenthese_level || eq_pos!=-1) break; + eq_pos=pos; + break; + + case '"': + if(in_comment) break; + in_string=!in_string; + break; + + case '{': + case '(': + case '[': + if(in_string || in_comment) break; + parenthese_level++; + break; + + case '}': + case ')': + case ']': + if(in_string || in_comment) break; + if(--parenthese_level<0) + { + write("Syntax error.\n"); + clean_buffer(); + return 0; + } + if(!parenthese_level && input[pos]=='}') + { + if(tmp=parse_function(input[0..pos])) + { + cut_buffer(pos+1); + if(stringp(tmp)) + set_buffer(tmp+input,1); + } + } + break; + + case ';': + if(in_string || in_comment || parenthese_level) break; + if(tmp=parse_statement(input[0..pos])) + { + cut_buffer(pos+1); + if(stringp(tmp)) + set_buffer(tmp+input,1); + } + break; + + case '*': + if(in_string || in_comment) break; + if(input[pos-1]=='/') in_comment=1; + break; + + case '/': + if(in_string) break; + if(input[pos-1]=='*') in_comment=0; + break; + } + } + if(pos>strlen(input)) pos=strlen(input); + return -1; + } + + + mixed parse_function(string fun) + { + string name,a,b; + object foo; + mixed c; +#ifdef DEBUG + write("Parsing block ("+first_word+")\n"); +#endif + + switch(first_word) + { + case "if": + case "for": + case "do": + case "while": + case "foreach": + /* parse loop */ + do_evaluate("mixed ___Foo4711() { "+fun+" ; }\n",0); + return 1; + + case "int": + case "void": + case "object": + case "array": + case "mapping": + case "string": + case "multiset": + case "float": + case "mixed": + case "program": + case "function": + case "class": + /* parse function */ + if(eq_pos!=-1) break; /* it's a variable */ + sscanf(fun,first_word+"%s",name); + + c=get_name(name); + name=c[0]; + c=c[1]; + + int i; + if((i=member_array(name,function_names))!=-1) + { + b=functions[i]; + functions[i]=fun; + if(!eval("")) functions[i]=b; + }else{ + if(eval(fun)) + { + functions+=({fun}); + function_names+=({name}); + } + } + return 1; + } + } + + mixed parse_statement(string ex) + { + string a,b,name; + mixed c; + object foo; + int e; +#ifdef DEBUG + write("Parsing statement ("+first_word+")\n"); +#endif + switch(first_word) + { + case "if": + case "for": + case "do": + case "while": + case "foreach": + /* parse loop */ + do_evaluate("mixed ___Foo4711() { "+ex+" ; }\n",0); + return 1; + + case "constant": + /* parse variable def. */ + sscanf(ex,first_word+"%s",b); + b=skipwhite(b); + c=get_name(b); + name=c[0]; + sscanf(c[1],"=%s",c[1]); + a=constants[name]; + constants[name]=c[1]; + if(!eval("")) constants[name]=a; + return 1; + + case "int": + case "void": + case "object": + case "array": + case "mapping": + case "string": + case "multiset": + case "float": + case "mixed": + case "program": + case "function": + /* parse variable def. */ + sscanf(ex,first_word+"%s",b); + b=skipwhite(b); + c=get_name(b); + name=c[0]; + c=c[1]; + +#ifdef DEBUG + write("Variable def.\n"); +#endif + if(name=="") + { + return 1; + }else{ + string f; + variables[name]=0; + + if(sscanf(c,"=%s",c)) + { +#ifdef DEBUG + write("Variable def. with assign. ("+name+")\n"); +#endif + if(e=find_next_comma(c)) + { + return name+"="+c[0..e-1]+";\n"+ + first_word+" "+c[e+1..strlen(c)-1]; + }else{ + return name+"="+c; + } +#ifdef DEBUG + write("Input buffer = '"+input+"'\n"); +#endif + + }else{ + sscanf(c,",%s",c); + return first_word+" "+c; + } + } + + return 1; + + default: + if(ex==";") return 1; + /* parse expressions */ + do_evaluate("mixed ___Foo4711() { return (mixed)("+ex[0..strlen(ex)-2]+"); }\n",1); + return 1; + } + } + + void add_input_line(string s) + { + string *tmp,a,b,c,f,name; + int e,d; + object foo; + + s=skipwhite(s); + + if(s[0..1]==".\n") + { + clean_buffer(); + write("Input buffer flushed.\n"); + s=s[2..strlen(s)-1]; + } + add_buffer(s); +// if(!strlen(input)) write("> "); + } + + void create() + { + print_version(); + } +} + +class StdinHilfe +{ + inherit Evaluator; + + void signal_trap(int s) + { + clean_buffer(); + throw("**Break\n"); + } + + void create() + { + write=predef::write; + ::create(); + + while(string s=readline(strlen(input) ? ">> " : "> ")) + { + signal(signum("SIGINT"),signal_trap); + add_input_line(s+"\n"); + signal(signum("SIGINT")); + } + write("Terminal closed.\n"); + } +} + +class GenericHilfe +{ + inherit Evaluator; + + void create(object(Stdio.FILE) in, object(Stdio.File) out) + { + write=out->write; + ::create(); + + while(1) + { + write(strlen(input) ? ">> " : "> "); + if(string s=in->gets()) + { + add_input_line(s+"\n"); + }else{ + write("Terminal closed.\n"); + return; + } + } + } +} + + +class GenericAsyncHilfe +{ + inherit Evaluator; + object(Stdio.File) infile, outfile; + + string outbuffer=""; + void write_callback() + { + int i=outfile->write(outbuffer); + outbuffer=outbuffer[i..]; + } + void send_output(string s, mixed ... args) + { + outbuffer+=sprintf(s,@args); + write_callback(); + } + + string inbuffer=""; + void read_callback(mixed id, string s) + { + inbuffer+=s; + foreach(inbuffer/"\n",string s) + { + add_input_line(s); + write(strlen(input) ? ">> " : "> "); + } + } + + void close_callback() + { + write("Terminal closed.\n"); + destruct(this_object()); + destruct(infile); + if(outfile) destruct(outfile); + } + + void create(object(Stdio.File) in, object(Stdio.File) out) + { + infile=in; + outfile=out; + in->set_nonblocking(read_callback, 0, close_callback); + out->set_write_callback(write_callback); + + write=send_output; + ::create(); + write(strlen(input) ? ">> " : "> "); + } +} +