/* $Id$ */ /* Command grammar */ { #include #include #include #include "ops.h" #include "class.h" #include "position.h" #include "file.h" #include "idf.h" #include "symbol.h" #include "tree.h" #include "langdep.h" #include "token.h" #include "expr.h" #include "misc.h" extern char *Salloc(); extern char *strchr(); extern char *strcpy(); extern void signal_child(); extern FILE *db_in; extern int disable_intr; extern p_tree run_command, print_command; struct token tok, aside; int errorgiven = 0; int child_interrupted = 0; int interrupted = 0; int eof_seen = 0; static int shellescape(); static int extended_charset = 0; static int in_expression = 0; #define binprio(op) ((*(currlang->binop_prio))(op)) #define unprio(op) ((*(currlang->unop_prio))(op)) } %start Commands, commands; %lexical LLlex; commands { p_tree com, lastcom = 0; int give_prompt; } : { errorgiven = 0; } [ %persistent command_line(&com) [ '\n' { give_prompt = 1; } | %default ';' { give_prompt = 0; } ] { if (com) { if (lastcom) { freenode(lastcom); lastcom = 0; } if (errorgiven) { if (com != run_command) freenode(com); com = 0; } else { enterlog(com); eval(com); if (repeatable(com)) { lastcom = com; } else if (! in_status(com) && com != run_command && com != print_command) { freenode(com); com = 0; } } } else if (lastcom && ! errorgiven) { enterlog(lastcom); eval(lastcom); } if (give_prompt) { errorgiven = 0; interrupted = 0; prompt(); } } ]* ; command_line(p_tree *p;) : { *p = 0; } [ list_command(p) | file_command(p) | run_command(p) | stop_command(p) | when_command(p) | continue_command(p) | step_command(p) | next_command(p) | regs_command(p) | where_command(p) | STATUS { *p = mknode(OP_STATUS); } | DUMP { *p = mknode(OP_DUMP); } | RESTORE opt_num(p) { *p = mknode(OP_RESTORE, *p); } | delete_command(p) | print_command(p) | display_command(p) | trace_command(p) | set_command(p) | help_command(p) | FIND qualified_name(p){ *p = mknode(OP_FIND, *p); } | WHICH qualified_name(p){ *p = mknode(OP_WHICH, *p); } | able_command(p) | '!' { (void) shellescape(); *p = mknode(OP_SHELL); } | source_command(p) | log_command(p) | frame_command(p) | ] ; frame_command(p_tree *p;) : FRAME [ { *p = mknode(OP_FRAME, (p_tree) 0); } | count(p) { *p = mknode(OP_FRAME, *p); } | '-' count(p) { *p = mknode(OP_DOWN, *p); } | '+' count(p) { *p = mknode(OP_UP, *p); } ] ; source_command(p_tree *p;) : SOURCE { extended_charset = 1; } name(p) { (*p)->t_idf = str2idf((*p)->t_str, 0); } { *p = mknode(OP_SOURCE, *p); extended_charset = 0; } ; log_command(p_tree *p;) : LOG { extended_charset = 1; } [ name(p) { (*p)->t_idf = str2idf((*p)->t_str, 0); } | { *p = 0; } ] { *p = mknode(OP_LOG, *p); extended_charset = 0; } ; where_command(p_tree *p;) : WHERE opt_num(p) { *p = mknode(OP_WHERE, *p); } ; list_command(p_tree *p;) { p_tree t1 = 0, t2 = 0; } : LIST [ | position(&t1) | qualified_name(&t1) ] [ ',' count(&t2) | '-' [ count(&t2) { t2->t_ival = - t2->t_ival; } | { t2 = mknode(OP_INTEGER, -100000000L); } ] | ] { *p = mknode(OP_LIST, t1, t2); } ; file_command(p_tree *p;) : XFILE { extended_charset = 1; } [ { *p = 0; } | name(p) { (*p)->t_idf = str2idf((*p)->t_str, 0); } ] { *p = mknode(OP_FILE, *p); extended_charset = 0; } ; help_command(p_tree *p;) : [ HELP | '?' ] { *p = mknode(OP_HELP, (p_tree) 0); } [ name(&(*p)->t_args[0])? | '?' { (*p)->t_args[0] = mknode(OP_NAME, str2idf("help",0), (char *) 0); } | '!' { (*p)->t_args[0] = mknode(OP_NAME, (struct idf *) 0, "!"); } ] ; run_command(p_tree *p;) : RUN { extended_charset = 1; } args(p) { *p = mknode(OP_RUN, *p); extended_charset = 0; } | RERUN { if (! run_command) { error("no run command given yet"); } else *p = run_command; } [ '?' { *p = mknode(OP_PRCOMM, *p); } | ] ; stop_command(p_tree *p;) { p_tree whr = 0, cond = 0; } : STOP where(&whr)? condition(&cond)? { if (! whr && ! cond) { error("no position or condition"); *p = 0; } else *p = mknode(OP_STOP, whr, cond); } ; trace_command(p_tree *p;) { p_tree whr = 0, cond = 0, exp = 0; } : TRACE [ ON format_expression(&exp) ]? where(&whr)? condition(&cond)? { *p = mknode(OP_TRACE, whr, cond, exp); } ; continue_command(p_tree *p;) { long l; p_tree pos = 0; } : CONT [ INTEGER { l = tok.ival; } | { l = 1; } ] [ AT position(&pos) ]? { *p = mknode(OP_CONT, mknode(OP_INTEGER, l), pos); } ; when_command(p_tree *p;) { p_tree whr = 0, cond = 0; } : WHEN where(&whr)? condition(&cond)? { *p = mknode(OP_WHEN, whr, cond, (p_tree) 0); p = &(*p)->t_args[2]; } '{' command_line(p) [ ';' { if (*p) { *p = mknode(OP_LINK, *p, (p_tree) 0); p = &((*p)->t_args[1]); } } command_line(p) ]* '}' { if (! whr && ! cond) { error("no position or condition"); } else if (! *p) { error("no commands given"); } } ; step_command(p_tree *p;) : STEP { *p = mknode(OP_STEP, (p_tree) 0); } count(&(*p)->t_args[0])? ; next_command(p_tree *p;) : NEXT { *p = mknode(OP_NEXT, (p_tree) 0); } count(&(*p)->t_args[0])? ; regs_command(p_tree *p;) : REGS { *p = mknode(OP_REGS, (p_tree) 0); } count(&(*p)->t_args[0])? ; delete_command(p_tree *p;) : DELETE num_list(p)? { *p = mknode(OP_DELETE, *p); } ; print_command(p_tree *p;) : PRINT [ format_expression_list(p) { *p = mknode(OP_PRINT, *p); } | { *p = mknode(OP_PRINT, (p_tree) 0); } ] ; display_command(p_tree *p;) : DISPLAY format_expression_list(p) { *p = mknode(OP_DISPLAY, *p); } ; format_expression_list(p_tree *p;) : format_expression(p) [ ',' { *p = mknode(OP_LINK, *p, (p_tree) 0); p = &((*p)->t_args[1]); } format_expression(p) ]* ; format_expression(p_tree *p;) { p_tree p1; } : expression(p, 0) [ '\\' name(&p1) { register char *c = p1->t_str; while (*c) { if (! strchr("doshcax", *c)) { error("illegal format: %c", *c); break; } c++; } *p = mknode(OP_FORMAT, *p, p1); } | ] ; set_command(p_tree *p;) : SET expression(p, 0) { *p = mknode(OP_SET, *p, (p_tree) 0); } TO expression(&((*p)->t_args[1]), 0) ; able_command(p_tree *p;) : [ ENABLE { *p = mknode(OP_ENABLE, (p_tree) 0); } | DISABLE { *p = mknode(OP_DISABLE, (p_tree) 0); } ] num_list(&(*p)->t_args[0])? ; num_list(p_tree *p;) : num(p) [ ',' { *p = mknode(OP_LINK, *p, (p_tree) 0); } num(&(*p)->t_args[1]) ]* ; condition(p_tree *p;) : IF expression(p, 0) ; where(p_tree *p;) : IN qualified_name(p) { *p = mknode(OP_IN, *p, (p_tree) 0); } [ AT position(&((*p)->t_args[1])) ]? | AT position(p) ; expression(p_tree *p; int level;) { int currprio, currop; } : { in_expression++; } factor(p) [ %while ((currprio = binprio(currop = (int) tok.ival)) > level) [ BIN_OP | PREF_OR_BIN_OP ] { *p = mknode(OP_BINOP, *p, (p_tree) 0); (*p)->t_whichoper = currop; } expression(&((*p)->t_args[1]), currprio) | SEL_OP { *p = mknode(OP_BINOP, *p, (p_tree) 0); (*p)->t_whichoper = (int) tok.ival; } name(&(*p)->t_args[1]) | '[' { *p = mknode(OP_BINOP, *p, (p_tree) 0); (*p)->t_whichoper = E_ARRAY; } expression(&(*p)->t_args[1], 0) [ ',' { *p = mknode(OP_BINOP, *p, (p_tree) 0); (*p)->t_whichoper = E_ARRAY; } expression(&(*p)->t_args[1], 0) ]* ']' ]* { in_expression--; } ; factor(p_tree *p;) : [ %default EXPRESSION /* lexical analyzer will never return this token */ { *p = mknode(OP_INTEGER, 0L); } | '(' expression(p, 0) ')' | INTEGER { *p = mknode(OP_INTEGER, tok.ival); } | REAL { *p = mknode(OP_REAL, tok.fval); } | STRING { *p = mknode(OP_STRING, tok.str); } | qualified_name(p) | { *p = mknode(OP_UNOP, (p_tree) 0); (*p)->t_whichoper = (int) tok.ival; } [ PREF_OP | PREF_OR_BIN_OP { (*currlang->fix_bin_to_pref)(*p); } ] expression(&(*p)->t_args[0], unprio((*p)->t_whichoper)) ] [ %while(1) POST_OP { *p = mknode(OP_UNOP, *p); (*p)->t_whichoper = (int) tok.ival; } ]* ; position(p_tree *p;) { p_tree lin; char *str; } : [ STRING { str = tok.str; } ':' | { if (! listfile) str = 0; else str = listfile->sy_idf->id_text; } ] count(&lin) { *p = mknode(OP_AT, lin->t_ival, str); freenode(lin); } ; args(p_tree *p;) { int first_time = 1; } : [ { if (! first_time) { *p = mknode(OP_LINK, *p, (p_tree) 0); p = &((*p)->t_args[1]); } first_time = 0; } arg(p) ]* ; arg(p_tree *p;) : name(p) | '>' name(p) { (*p)->t_oper = OP_OUTPUT; } | '<' name(p) { (*p)->t_oper = OP_INPUT; } ; count(p_tree *p;) : INTEGER { *p = mknode(OP_INTEGER, tok.ival); } ; opt_num(p_tree *p;) : num(p) | { *p = 0; } ; num(p_tree *p;) : count(p) | '-' count(p) { (*p)->t_ival = - (*p)->t_ival; } ; qualified_name(p_tree *p;) : name(p) [ '`' { *p = mknode(OP_SELECT, *p, (p_tree) 0); } name(&((*p)->t_args[1])) ]* ; name(p_tree *p;) : [ XFILE | LIST | RUN | RERUN | STOP | WHEN | AT | IN | IF | %default NAME | CONT | STEP | NEXT | REGS | WHERE | STATUS | PRINT | DELETE | DUMP | RESTORE | TRACE | ON | SET | TO | FIND | DISPLAY | WHICH | HELP | DISABLE | ENABLE | SOURCE | FRAME | LOG ] { *p = mknode(OP_NAME, tok.idf, tok.str); } ; { int LLlex() { register int c; if (ASIDE) { tok = aside; ASIDE = 0; return TOK; } do { c = getc(db_in); if (interrupted && c == EOF) { c = ' '; interrupted = 0; continue; } } while (c != EOF && class(c) == STSKIP); if (c == EOF) { eof_seen = 1; return c; } if (extended_charset && in_ext(c)) { TOK = get_name(c); return TOK; } switch(class(c)) { case STSTR: TOK = (*currlang->get_string)(c); break; case STIDF: if (in_expression) TOK = (*currlang->get_name)(c); else TOK = get_name(c); break; case STNUM: TOK = (*currlang->get_number)(c); break; case STNL: TOK = c; break; case STSIMP: if (! in_expression) { TOK = c; break; } /* Fall through */ default: TOK = (*currlang->get_token)(c); break; } return TOK; } int get_name(c) register int c; { char buf[512+1]; register char *p = &buf[0]; register struct idf *id; do { if (p - buf < 512) *p++ = c; c = getc(db_in); } while ((extended_charset && in_ext(c)) || in_idf(c)); ungetc(c, db_in); *p++ = 0; if (extended_charset) { tok.idf = 0; tok.str = Salloc(buf, (unsigned) (p - buf)); return NAME; } id = str2idf(buf, 1); tok.idf = id; tok.str = id->id_text; return id->id_reserved ? id->id_reserved : NAME; } extern char *symbol2str(); LLmessage(t) { if (t > 0) { if (! errorgiven) { error("%s missing before %s", symbol2str(t), symbol2str(TOK)); } aside = tok; } else if (t == 0) { if (! errorgiven) { error("%s unexpected", symbol2str(TOK)); } } else if (! errorgiven) { error("EOF expected"); } errorgiven = 1; } static void catch_del() { signal(SIGINT, catch_del); if (! disable_intr) { signal_child(7); child_interrupted = 1; } interrupted = 1; } void init_del() { signal(SIGINT, catch_del); } static void ctch() { /* Only for shell escapes ... */ signal(SIGINT, ctch); } #define SHBUFSIZ 512 static int shellescape() { register char *p; /* walks through command */ static char previous[SHBUFSIZ]; /* previous command */ char comm[SHBUFSIZ]; /* space for command */ register int cnt; /* prevent array bound errors */ register int c; /* current char */ register int lastc = 0; /* will contain the previous char */ p = comm; cnt = SHBUFSIZ-2; while (c = getc(db_in), c != '\n') { switch(c) { case '!': /* * An unescaped ! expands to the previous * command, but disappears if there is none */ if (lastc != '\\') { if (*previous) { int len = strlen(previous); if ((cnt -= len) <= 0) break; strcpy(p,previous); p += len; } } else { *p++ = c; } continue; case '%': /* * An unescaped % will expand to the current * filename, but disappears is there is none */ if (lastc != '\\') { if (listfile) { int len = strlen(listfile->sy_idf->id_text); if ((cnt -= len) <= 0) break; strcpy(p,listfile->sy_idf->id_text); p += len; } } else { *p++ = c; } continue; default: lastc = c; if (cnt-- <= 0) break; *p++ = c; continue; } break; } *p = '\0'; if (c != '\n') { warning("shell command too long"); while (c != '\n') c = getc(db_in); } ungetc(c, db_in); strcpy(previous, comm); signal(SIGINT, ctch); cnt = system(comm); signal(SIGINT, catch_del); return cnt; } }