%pure_parser %{ // Rascal, the Advanced Scientific CALculator // Copyright (C) 2001, 2002, Sebastian Ritterbusch (Rascal@Ritterbusch.de) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include #include "symtab.h" #include "value.hpp" extern int rascal_user_stop; value eval(string a); %} %union { value *val; symrec *tptr; } %{ /* */ #include #include #include #include extern "C" { #include } int precis=8; void * set_string_input(char *); void reset_input(void *); value result; void yyerror(char *s); int yylex(YYSTYPE *yylval); %} %token PARSERnumber PARSERfor PARSERhelp %token PARSERvariable PARSERfunction PARSERfunction2 PARSERuserfunction PARSERprocedure %token PARSERfunctionDefinition %token PARSERbecomes PARSERlparent PARSERrparent PARSERnewline %token PARSERlbracket PARSERrbracket PARSERcomma %token PARSERat %left PARSERwhite %left PARSERbecomes %left PARSERsemicolon %left PARSERML %left PARSERquestionmark %left PARSERcolon %left PARSERLT PARSERLE PARSERGT PARSERGE %left PARSEREQ PARSERNEQ %left PARSERAND %left PARSEROR %left PARSERplus PARSERminus %left PARSERplusplus PARSERminusminus %left PARSERtimes PARSERdivide PARSERmodulo %right PARSERpower PARSERtranspose PARSERFAC PARSERNOT %right PARSERlparent %type PARSERexpr %type PARSERmatrix %type PARSERmatrixline %type PARSERexprlist %% PARSERlist: { } | PARSERlist PARSERexpr PARSERnewline { result=*($2); if(!rascal_user_stop) { value o(output(*($2))); if(o.isSTRING()) printf(" %s\n",o.asSTRING().c_str()); else printf(" Error.\n"); } delete $2; } | PARSERlist PARSERexpr PARSERsemicolon { result=*($2); delete $2; } | PARSERlist PARSERfunctionDefinition { } | PARSERlist PARSERuserfunction PARSERnewline { printf("%s%s\n",$2->name,$2->ivalue.body); } | PARSERlist PARSERfunction PARSERnewline { printf("%s is a built-in unary function.\n",$2->name); } | PARSERlist PARSERfunction2 PARSERnewline { printf("%s is a built-in binary function.\n",$2->name); } | PARSERlist PARSERhelp { int i; string helpstring=$2->asSTRING(); delete $2; string keyword; // for(i=0;i' to view.\n"); } else { for(i=0;rascal_help_indices[i] && rascal_help_indices[i]!=keyword;i++); if(rascal_help_indices[i]) printf("%s\n",rascal_help_data[i]); else if(keyword=="") { printf("%s\n",rascal_help_data[0]); } else { int found=0; int foundid=0; for(i=0;rascal_help_indices[i];i++) if(string(rascal_help_data[i]).find(keyword)!=string::npos) { found++; foundid=i; } if(found==0 || found>50) printf("%s\n",rascal_help_data[0]); else if(found==1) { printf("This topic is unknown, but perhaps this might help:\n"); printf("help %s\n",rascal_help_indices[foundid]); // printf("%s\n",rascal_help_data[foundid]); } else { printf("This topic is unknown, but perhaps one of the following may help:\n"); for(i=0;rascal_help_indices[i];i++) if(string(rascal_help_data[i]).find(keyword)!=string::npos) printf("%s\n",rascal_help_indices[i]); printf("\nEnter 'help ' to view.\n"); } } } } | PARSERlist PARSERnewline { } | PARSERlist PARSERsemicolon { } | PARSERlist error PARSERnewline { yyerrok; yyclearin; } | PARSERlist PARSERfor PARSERnewline { string a=$2->asSTRING(); delete $2; string init,cond,incr,comm; int i; for(i=0;iasMATRIX(),1),cell(($2)->asMATRIX(),2))); delete $2; } | PARSERwhite PARSERexpr %prec PARSERbecomes { $$ = $2; } | PARSERnumber { $$ = $1; } | PARSERvariable { $$ = new value($1->var); } | PARSERvariable PARSERplusplus { $1->var=$1->var+1; $$ = new value($1->var); } | PARSERvariable PARSERminusminus { $1->var=$1->var-1; $$ = new value($1->var); } | PARSERvariable PARSERbecomes PARSERexpr { $$ = $3; $1->var=*($3);} | PARSERprocedure { $$=new value( (*($1->ivalue.procptr))() ); } | PARSERexpr PARSERlbracket PARSERmatrix PARSERrbracket { if($1->isSYMREC()) $$=new value(evaluate($1->asSYMREC(),*$3)); else $$=new value( cell(*$1,*$3)); delete $1;delete $3; } | PARSERexpr PARSERlparent PARSERexpr PARSERrparent { if($1->isSYMREC()) $$=new value(evaluate($1->asSYMREC(),*$3)); else $$=new value( cell(*$1,*$3)); delete $1;delete $3; } | PARSERexpr PARSERlparent PARSERexprlist PARSERrparent { if($1->isSYMREC()) $$=new value(evaluate_n($1->asSYMREC(),$3->asMATRIX())); else $$=new value( cell(*$1,$3->asMATRIX() ) ); delete $1;delete $3; } | PARSERexpr PARSERquestionmark PARSERexpr PARSERcolon PARSERexpr { $$ = new value((($1)->isINTEGER() && ($1)->asINTEGER())?*($3):*($5)); delete $1;delete $3;delete $5;} | PARSERexpr PARSERplus PARSERexpr { $$ = new value(add(*($1),*($3))); delete $1;delete $3; } | PARSERexpr PARSERminus PARSERexpr { $$ = new value(sub(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERtimes PARSERexpr { $$ = new value(mul(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERdivide PARSERexpr { $$ = new value(div(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERmodulo PARSERexpr { $$ = new value(mod(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERpower PARSERexpr { $$ = new value(pow(*($1),*($3)));delete $1;delete $3;} | PARSERexpr PARSERLT PARSERexpr { $$ = new value(less(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERLE PARSERexpr { $$ = new value(lesseq(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERGT PARSERexpr { $$ = new value(greater(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERGE PARSERexpr { $$ = new value(greatereq(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSEREQ PARSERexpr { $$ = new value(eq(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERNEQ PARSERexpr { $$ = new value(neq(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSERAND PARSERexpr { $$ = new value(And(*($1),*($3))); delete $1;delete $3;} | PARSERexpr PARSEROR PARSERexpr { $$ = new value(Or(*($1),*($3))); delete $1;delete $3;} | PARSERNOT PARSERexpr { $$ = new value(Not(*($2)));delete $2; } | PARSERexpr PARSERFAC { $$ = new value(fac(*($1))); delete $1;} | PARSERexpr PARSERtranspose { $$ = new value(transpose(*($1))); delete $1; } | PARSERlparent PARSERexpr PARSERrparent { $$ = $2; } | PARSERminus PARSERexpr %prec PARSERtimes { $$ = new value(neg(*($2)));delete $2;} | PARSERlbracket PARSERmatrix PARSERrbracket { $$=$2; } /* | PARSERlparent PARSERexprlist PARSERrparent { $$=$2; } exprlistdebug*/ ; PARSERmatrix: PARSERmatrixline { $$ = $1; } | PARSERmatrix PARSERsemicolon PARSERmatrixline { $$ = new value(appendline($1->asMATRIX(),$3->asMATRIX() )); delete $1; delete $3;} | PARSERmatrix PARSERsemicolon PARSERexpr { $$ = new value(appendline($1->asMATRIX(),valuematrix(*$3) )); delete $1; delete $3; } ; PARSERmatrixline: PARSERmatrixline PARSERwhite PARSERexpr %prec PARSERML { $$ = new value(appendcol($1->asMATRIX(),valuematrix(*($3)))); delete $1; delete $3;} | PARSERexpr %prec PARSERML { $$=new value(valuematrix(*$1)); delete $1; } ; PARSERexprlist: PARSERexprlist PARSERcomma PARSERexpr { $$ = new value(appendcol($1->asMATRIX(),valuematrix(*($3)))); delete $1; delete $3;} | PARSERexpr PARSERcomma PARSERexpr { $$ = new value(appendcol(valuematrix(*($1)),valuematrix(*($3)))); delete $1; delete $3;} ; %% #include extern "C" { #include #include } #include #include extern char *xmalloc(int); int colour_support=0; int shell_colour=4; int output_colour=0; void set_shell_colour(void) { if(colour_support) { char dummy[40]; sprintf(dummy,"tput setaf %d",shell_colour); system(dummy); } } void set_output_colour(void) { if(colour_support) { char dummy[40]; sprintf(dummy,"tput setaf %d",output_colour); system(dummy); } } char * dupstr(char *s) { char *r=(char *)malloc(strlen(s)+1); strcpy(r,s); return r; } char * dupstr_function(char *s) { char *r=(char *)malloc(strlen(s)+2); strcpy(r,s); strcat(r,"("); return r; } char * command_generator(const char *text,int state) { static symrec * current; static int len; if(state==0) { current=sym_table; len=strlen(text); } while(current) { if(len==0 || strncmp(current->name,text,len)==0) { char *p=current->name; int type=current->type; const value &v(current->var); current=current->next; if(type==PARSERvariable) { if(v!=value(0)) return dupstr(p); } else if(type==PARSERprocedure) return dupstr(p); else return dupstr_function(p); } current=current->next; } return ((char *)NULL); } char **rascal_completition(const char *text,int start,int end) { return rl_completion_matches(text,command_generator); } void initialize_readline(void) { rl_readline_name="Rascal"; rl_attempted_completion_function=rascal_completition; rl_basic_word_break_characters="+-*/; ^|&<>=?:(),"; init_table(); } value eval(string input_lf) { int i; // dirty parser-fix, remove all spaces exterior to '[',']' string input_fixed; int bracket_depth=0,string_on=0; for(i=0;i0 && input_lf[i]==']') { input_fixed+=input_lf[i]; bracket_depth--; } else if(input_lf[i]=='"') { input_fixed+=input_lf[i]; string_on^=1; } else if(bracket_depth==0 && string_on==0 && (input_lf[i]==' ' || input_lf[i]=='\t')) { // skip ws } else input_fixed+=input_lf[i]; } void *buffer=set_string_input((char *)(input_fixed.c_str())); yyparse(); value res(result); reset_input(buffer); return res; } int load(string a) { ifstream in(a.c_str()); if(in.fail()) return 1; while(!in.fail() && !in.eof()) { string b; getline(in,b); eval(b+"\n"); } return 0; } int rascal_user_stop=0; int rascal_in_readline=0; void sigint_handler(int) { if(!rascal_user_stop) { rascal_user_stop=1; if(rascal_in_readline) { cerr << char(7); } else cerr << "\nbreak requested.\n"; } else { cerr << "\ntermination due to user signal.\n"; set_output_colour(); exit(1); } } int main(int argc, char *argv[]) { int digit_optind = 0; int quiet=0; int norc=0; signal(SIGINT,sigint_handler); string doeval; while (1) { int this_option_optind = digit_optind ? digit_optind : 1; int option_index = 0; static struct option long_options[] = { {"evaluate", 1, 0, 'e'}, {"quiet", 0, 0, 'q'}, {"help",0,0,'h'}, {"norc",0,0,'n'}, {"version", 0, 0, 0}, {"licence", 0, 0, 1}, {"shellcolour",1,0,2}, {"outputcolour",1,0,3}, {0, 0, 0, 0} }; char c = getopt_long (argc, argv, "e:qhn", long_options, &option_index); if (c == -1) break; switch (c) { case 0: #ifdef VALUE_CONFIGURATION if(VALUE_CONFIGURATION!=string("full")) cout << "Rascal-" << VALUE_CONFIGURATION << "-" << VERSION; else cout << "Rascal-" << VERSION; #else cout << "Rascal-" << VERSION; #endif cout << endl; return 0; case 1: eval("licence;\nquit\n"); return 0; case 2: colour_support=1; shell_colour=atoi(optarg); break; case 3: colour_support=1; output_colour=atoi(optarg); break; case 'h': cout << "Usage: rascal [options] [file...] " << endl; cout << endl; cout << "Options:" << endl; cout << " -h, --h(elp) displays this message" << endl; cout << " -e, --e(valuate) evaluates the following expression and terminates" << endl; cout << " -q, --q(uiet) prevents startup message" << endl; cout << " -n, --n(orc) prevents loading of rc file" << endl; cout << " --v(ersion) displays version information" << endl; cout << " --l(icence) displays licence information" << endl; cout << " --shellcolour set following shell colour (experimental)" << endl; cout << " --outputcolour set following output colour (experimental)" << endl; cout << endl; cout << " The content of given files and expressions will be treated as user input" << endl; cout << " in the order rc-file, given files, expressions." << endl; cout << endl; cout << " The rc-file is searched in %%PREFIX%%/etc/rascal.rc, rascal.rc" << endl; return 0; case 'n': norc=1; break; case 'q': quiet=1; break; case 'e': doeval+=string(optarg)+"\n"; quiet=1; break; default: cerr << "Unknown option -" << c << endl; return 1; } } set_output_colour(); if(!quiet) { #ifdef VALUE_CONFIGURATION if(VALUE_CONFIGURATION!=string("full")) cout << "Rascal-" << VALUE_CONFIGURATION << "-" << VERSION; else cout << "Rascal-" << VERSION; #else cout << "Rascal-" << VERSION; #endif cout << " (C) 2001,2002 Sebastian Ritterbusch" << endl; cout << endl; cout << "Enter 'help' for help or 'licence' for information about licence and warranty." << endl; cout << endl; } if(norc==0) if(load("%%PREFIX%%/etc/rascal.rc") && load("rascal.rc")) ; // no rcfile found if(doeval!="") { eval(doeval); return 0; } if (optind < argc) { while (optind < argc) { if(load(argv[optind++])) cout << "Couldn't read " << argv[optind-1] << endl; } } // Without readline just: yyparse(); // but with... initialize_readline(); while(cin) { char *input=0; set_shell_colour(); do { if(input) free(input); rascal_in_readline=1; rascal_user_stop=0; input=readline(">"); rascal_in_readline=0; rascal_user_stop=0; if(!input) return 0; } while(!input || input[0]==0); set_output_colour(); string input_lf(input+string("\n")); value res; try { res=output(eval(input_lf)); } catch (...) { res=value("Error"); } add_history(input); if(res.isSTRING() && res.asSTRING()!="Error" && res.asSTRING()!="0") add_history((char *)(res.asSTRING().c_str())); } cout << endl; return 0; } void yyerror(char *s) { printf("%s\n",s); }