/* $Header$ */ /* Command grammar */ { #include #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" extern char *Salloc(); extern t_lineno currline; extern FILE *db_in; int errorgiven; static int extended_charset = 0; static int in_expression = 0; jmp_buf jmpbuf; static int init_del(); static int skip_to_eol(); struct token tok, aside; #define prio(op) ((*(currlang->op_prio))(op)) } %start Commands, commands; %lexical LLlex; commands { p_tree com, lastcom = 0; } : { if (! setjmp(jmpbuf)) { init_del(); } else { skip_to_eol(); goto prmpt; } } [ %persistent command_line(&com) { if (com) { if (errorgiven) { freenode(com); com = 0; } if (lastcom && !in_status(lastcom) && lastcom != run_command) { freenode(lastcom); lastcom = 0; } if (com) { if (repeatable(com)) { lastcom = com; } eval(com); if (! repeatable(com) && ! in_status(com) && com != run_command) { freenode(com); } } } else if (lastcom && ! errorgiven) eval(lastcom); } [ '\n' { prmpt: prompt(); } | ';' ] { errorgiven = 0; } ]* { signal_child(SIGKILL); } ; command_line(p_tree *p;) : 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 { *p = mknode(OP_WHERE); } | STATUS { *p = mknode(OP_STATUS); } | DUMP { *p = mknode(OP_DUMP); } | RESTORE INTEGER { *p = mknode(OP_RESTORE, tok.ival); } | delete_command(p) | print_command(p) | trace_command(p) | { *p = 0; } ; list_command(p_tree *p;) { p_tree t1 = 0, t2 = 0; } : LIST [ | lin_num(&t1) [ ',' lin_num(&t2) | { t2 = mknode(OP_INTEGER, t1->t_ival); } ] ] { *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; } ; run_command(p_tree *p;) : RUN { extended_charset = 1; *p = 0; } args(p) { *p = mknode(OP_RUN, *p); extended_charset = 0; freenode(run_command); run_command = *p; } | RERUN { if (! run_command) { error("no run command given yet"); } else *p = run_command; } ; 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 expression(&exp, 1) ]? 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; } ] 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)? '{' command_line(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"); freenode(*p); *p = 0; } else *p = mknode(OP_WHEN, whr, cond, *p); } ; step_command(p_tree *p;) { long l; } : STEP [ INTEGER { l = tok.ival; } | { l = 1; } ] { *p = mknode(OP_STEP, l); } ; next_command(p_tree *p;) { long l; } : NEXT [ INTEGER { l = tok.ival; } | { l = 1; } ] { *p = mknode(OP_NEXT, l); } ; regs_command(p_tree *p;) { long l; } : REGS [ INTEGER { l = tok.ival; } | { l = 0; } ] { *p = mknode(OP_REGS, l); } ; delete_command(p_tree *p;) : DELETE INTEGER { *p = mknode(OP_DELETE, tok.ival); } ; print_command(p_tree *p;) : PRINT expression(p, 1){ *p = mknode(OP_PRINT, *p); p = &((*p)->t_args[0]); } [ ',' { *p = mknode(OP_LINK, *p, (p_tree) 0); p = &((*p)->t_args[1]); } expression(p, 1) ]* ; condition(p_tree *p;) : IF expression(p, 1) ; where(p_tree *p;) : IN qualified_name(p) { *p = mknode(OP_IN, *p); } | position(p) ; expression(p_tree *p; int level;) { int currprio, currop; } : { in_expression++; } factor(p) [ %while ((currprio = prio(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) ]* { in_expression--; } ; factor(p_tree *p;) : '(' expression(p, 1) ')' | INTEGER { *p = mknode(OP_INTEGER, tok.ival); } | REAL { *p = mknode(OP_REAL, tok.fval); } | STRING { *p = mknode(OP_STRING, tok.str); } | designator(p) | PREF_OP { *p = mknode(OP_UNOP, (p_tree) 0); (*p)->t_whichoper = (int) tok.ival; } factor(&(*p)->t_args[0]) ; designator(p_tree *p;) : qualified_name(p) [ 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 = '['; } expression(&(*p)->t_args[1], 1) ']' | POST_OP { *p = mknode(OP_UNOP, *p); (*p)->t_whichoper = (int) tok.ival; } ]* ; position(p_tree *p;) { p_tree lin; char *str; } : AT [ STRING { str = tok.str; } ':' | { if (! currfile) str = 0; else str = currfile->sy_idf->id_text; } ] lin_num(&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; } ; lin_num(p_tree *p;) : INTEGER { *p = mknode(OP_INTEGER, tok.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 | NAME | CONT | STEP | NEXT | REGS | WHERE | STATUS | PRINT | DELETE | DUMP | RESTORE | TRACE | ON ] { *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); } while (c != EOF && class(c) == STSKIP); if (c == EOF) return c; 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 STDOT: c = getc(db_in); if (c == EOF || class(c) != STNUM) { ungetc(c,db_in); TOK = '.'; break; } /* Fall through */ 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; } static int quoted(ch) int ch; { /* quoted() replaces an escaped character sequence by the character meant. */ /* first char after backslash already in ch */ if (!is_oct(ch)) { /* a quoted char */ switch (ch) { case 'n': ch = '\n'; break; case 't': ch = '\t'; break; case 'b': ch = '\b'; break; case 'r': ch = '\r'; break; case 'f': ch = '\f'; break; } } else { /* a quoted octal */ register int oct = 0, cnt = 0; do { oct = oct*8 + (ch-'0'); ch = getc(db_in); } while (is_oct(ch) && ++cnt < 3); ungetc(ch, db_in); ch = oct; } return ch&0377; } int get_string(c) int c; { register int ch; char buf[512]; register int len = 0; while (ch = getc(db_in), ch != c) { if (ch == '\n') { error("newline in string"); break; } if (ch == '\\') { ch = getc(db_in); ch = quoted(ch); } buf[len++] = ch; } buf[len++] = 0; tok.str = Salloc(buf, (unsigned) len); return STRING; } static int val_in_base(c, base) register int c; { return is_dig(c) ? c - '0' : base != 16 ? -1 : is_hex(c) ? (c - 'a' + 10) & 017 : -1; } int get_number(c) register int c; { char buf[512+1]; register int base = 10; register char *p = &buf[0]; register long val = 0; register int val_c; if (c == '0') { /* check if next char is an 'x' or an 'X' */ c = getc(db_in); if (c == 'x' || c == 'X') { base = 16; c = getc(db_in); } else base = 8; } while (val_c = val_in_base(c, base), val_c >= 0) { val = val * base + val_c; if (p - buf < 512) *p++ = c; c = getc(db_in); } if (base == 16 || !((c == '.' || c == 'e' || c == 'E'))) { ungetc(c, db_in); tok.ival = val; return INTEGER; } if (c == '.') { if (p - buf < 512) *p++ = c; c = getc(db_in); } while (is_dig(c)) { if (p - buf < 512) *p++ = c; c = getc(db_in); } if (c == 'e' || c == 'E') { if (p - buf < 512) *p++ = c; c = getc(db_in); if (c == '+' || c == '-') { if (p - buf < 512) *p++ = c; c = getc(db_in); } if (! is_dig(c)) { error("malformed floating constant"); } while (is_dig(c)) { if (p - buf < 512) *p++ = c; c = getc(db_in); } } ungetc(c, db_in); *p++ = 0; if (p == &buf[512+1]) { error("floating point constant too long"); } return REAL; } 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 int catch_del() { signal(SIGINT, catch_del); signal_child(SIGEMT); longjmp(jmpbuf, 1); } static int init_del() { signal(SIGINT, catch_del); } static int skip_to_eol() { while (TOK != '\n' && TOK > 0) LLlex(); wait_for_child("interrupted"); } }