1 #include "rc.h" 2 #include "y.tab.h" 3 4 #define NTOK 8192 5 6 int getnext(void); 7 8 int future=EOF; 9 int doprompt=1; 10 int inquote; 11 int nerror; 12 char *promptstr; 13 14 char tok[NTOK]; 15 16 int lastdol; /* was the last token read '$' or '$#' or '"'? */ 17 int lastword; /* was the last token read a word or compound word terminator? */ 18 int lastc; 19 20 void 21 kinit(void) 22 { 23 kenter(FOR, "for"); 24 kenter(IN, "in"); 25 kenter(WHILE, "while"); 26 kenter(IF, "if"); 27 kenter(NOT, "not"); 28 kenter(TWIDDLE, "~"); 29 kenter(BANG, "!"); 30 kenter(SUBSHELL, "@"); 31 kenter(SWITCH, "switch"); 32 kenter(FN, "fn"); 33 } 34 35 int 36 wordchr(int c) 37 { 38 return !strchr("\n \t\r#;&|^$=`'{}()<>", c) && c!=EOF; 39 } 40 41 int 42 idchr(int c) 43 { 44 /* 45 * Formerly: 46 * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9' 47 * || c=='_' || c=='*'; 48 */ 49 return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c); 50 } 51 52 /* 53 * Look ahead in the input stream 54 */ 55 int 56 nextc(void) 57 { 58 if(future==EOF) 59 future=getnext(); 60 return future; 61 } 62 63 /* 64 * Consume the lookahead character. 65 */ 66 int 67 advance(void) 68 { 69 int c=nextc(); 70 lastc=future; 71 future=EOF; 72 return c; 73 } 74 75 /* 76 * read a character from the input stream 77 */ 78 int 79 getnext(void) 80 { 81 register int c; 82 static peekc=EOF; 83 if(peekc!=EOF){ 84 c=peekc; 85 peekc=EOF; 86 return c; 87 } 88 if(runq->eof) return EOF; 89 if(doprompt) 90 pprompt(); 91 c=rchr(runq->cmdfd); 92 if(!inquote && c=='\\'){ 93 c=rchr(runq->cmdfd); 94 if(c=='\n'){ 95 doprompt=1; 96 c=' '; 97 } 98 else{ 99 peekc=c; 100 c='\\'; 101 } 102 } 103 doprompt=doprompt || c=='\n' || c==EOF; 104 if(c==EOF) runq->eof++; 105 else if(flag['V'] || ndot>=2 && flag['v']) 106 pchr(err, c); 107 return c; 108 } 109 110 void 111 pprompt(void) 112 { 113 Var *prompt; 114 115 if(runq->iflag){ 116 pstr(err, promptstr); 117 flush(err); 118 prompt=vlook("prompt"); 119 if(prompt->val && prompt->val->next) 120 promptstr=prompt->val->next->word; 121 else 122 promptstr="\t"; 123 } 124 runq->lineno++; 125 doprompt=0; 126 } 127 128 void 129 skipwhite(void) 130 { 131 int c; 132 for(;;){ 133 c=nextc(); 134 if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */ 135 for(;;){ 136 c=nextc(); 137 if(c=='\n' || c==EOF) break; 138 advance(); 139 } 140 } 141 if(c==' ' || c=='\t' || c=='\r') advance(); 142 else return; 143 } 144 } 145 146 void 147 skipnl(void) 148 { 149 int c; 150 for(;;){ 151 skipwhite(); 152 c=nextc(); 153 if(c!='\n') return; 154 advance(); 155 } 156 } 157 158 int 159 nextis(int c) 160 { 161 if(nextc()==c){ 162 advance(); 163 return 1; 164 } 165 return 0; 166 } 167 168 char * 169 addtok(char *p, int val) 170 { 171 if(p==0) return 0; 172 if(p==&tok[NTOK]){ 173 *p=0; 174 yyerror("token buffer too short"); 175 return 0; 176 } 177 *p++=val; 178 return p; 179 } 180 181 char * 182 addutf(char *p, int c) 183 { 184 p=addtok(p, c); 185 if(twobyte(c)) /* 2-byte escape */ 186 return addtok(p, advance()); 187 if(threebyte(c)){ /* 3-byte escape */ 188 p=addtok(p, advance()); 189 return addtok(p, advance()); 190 } 191 return p; 192 } 193 194 int 195 yylex(void) 196 { 197 int c, d=nextc(); 198 char *w=tok; 199 Tree *t; 200 201 yylval.tree=0; 202 /* 203 * Embarassing sneakiness: if the last token read was a quoted or unquoted 204 * WORD then we alter the meaning of what follows. If the next character 205 * is `(', we return SUB (a subscript paren) and consume the `('. Otherwise, 206 * if the next character is the first character of a simple or compound word, 207 * we insert a `^' before it. 208 */ 209 if(lastword){ 210 lastword=0; 211 if(d=='('){ 212 advance(); 213 strcpy(tok, "( [SUB]"); 214 return SUB; 215 } 216 if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){ 217 strcpy(tok, "^"); 218 return '^'; 219 } 220 } 221 inquote=0; 222 skipwhite(); 223 switch(c=advance()){ 224 case EOF: 225 lastdol=0; 226 strcpy(tok, "EOF"); 227 return EOF; 228 case '$': 229 lastdol=1; 230 if(nextis('#')){ 231 strcpy(tok, "$#"); 232 return COUNT; 233 } 234 if(nextis('"')){ 235 strcpy(tok, "$\""); 236 return '"'; 237 } 238 strcpy(tok, "$"); 239 return '$'; 240 case '&': 241 lastdol=0; 242 if(nextis('&')){ 243 skipnl(); 244 strcpy(tok, "&&"); 245 return ANDAND; 246 } 247 strcpy(tok, "&"); 248 return '&'; 249 case '|': 250 lastdol=0; 251 if(nextis(c)){ 252 skipnl(); 253 strcpy(tok, "||"); 254 return OROR; 255 } 256 case '<': 257 case '>': 258 lastdol=0; 259 /* 260 * funny redirection tokens: 261 * redir: arrow | arrow '[' fd ']' 262 * arrow: '<' | '<<' | '>' | '>>' | '|' 263 * fd: digit | digit '=' | digit '=' digit 264 * digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' 265 * some possibilities are nonsensical and get a message. 266 */ 267 *w++=c; 268 t=newtree(); 269 switch(c){ 270 case '|': 271 t->type=PIPE; 272 t->fd0=1; 273 t->fd1=0; 274 break; 275 case '>': 276 t->type=REDIR; 277 if(nextis(c)){ 278 t->rtype=APPEND; 279 *w++=c; 280 } 281 else t->rtype=WRITE; 282 t->fd0=1; 283 break; 284 case '<': 285 t->type=REDIR; 286 if(nextis(c)){ 287 t->rtype=HERE; 288 *w++=c; 289 } 290 else t->rtype=READ; 291 t->fd0=0; 292 break; 293 } 294 if(nextis('[')){ 295 *w++='['; 296 c=advance(); 297 *w++=c; 298 if(c<'0' || '9'<c){ 299 RedirErr: 300 *w=0; 301 yyerror(t->type==PIPE?"pipe syntax" 302 :"redirection syntax"); 303 return EOF; 304 } 305 t->fd0=0; 306 do{ 307 t->fd0=t->fd0*10+c-'0'; 308 *w++=c; 309 c=advance(); 310 }while('0'<=c && c<='9'); 311 if(c=='='){ 312 *w++='='; 313 if(t->type==REDIR) 314 t->type=DUP; 315 c=advance(); 316 if('0'<=c && c<='9'){ 317 t->rtype=DUPFD; 318 t->fd1=t->fd0; 319 t->fd0=0; 320 do{ 321 t->fd0=t->fd0*10+c-'0'; 322 *w++=c; 323 c=advance(); 324 }while('0'<=c && c<='9'); 325 } 326 else{ 327 if(t->type==PIPE) goto RedirErr; 328 t->rtype=CLOSE; 329 } 330 } 331 if(c!=']' || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND)) 332 goto RedirErr; 333 *w++=']'; 334 } 335 *w='\0'; 336 yylval.tree=t; 337 if(t->type==PIPE) skipnl(); 338 return t->type; 339 case '\'': 340 lastdol=0; 341 lastword=1; 342 inquote=1; 343 for(;;){ 344 c=advance(); 345 if(c==EOF) break; 346 if(c=='\''){ 347 if(nextc()!='\'') 348 break; 349 advance(); 350 } 351 w=addutf(w, c); 352 } 353 if(w!=0) *w='\0'; 354 t=token(tok, WORD); 355 t->quoted=1; 356 yylval.tree=t; 357 return t->type; 358 } 359 if(!wordchr(c)){ 360 lastdol=0; 361 tok[0]=c; 362 tok[1]='\0'; 363 return c; 364 } 365 for(;;){ 366 /* next line should have (char)c==GLOB, but ken's compiler is broken */ 367 if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB) 368 w=addtok(w, GLOB); 369 w=addutf(w, c); 370 c=nextc(); 371 if(lastdol?!idchr(c):!wordchr(c)) break; 372 advance(); 373 } 374 Out: 375 lastword=1; 376 lastdol=0; 377 if(w!=0) *w='\0'; 378 t=klook(tok); 379 if(t->type!=WORD) lastword=0; 380 t->quoted=0; 381 yylval.tree=t; 382 return t->type; 383 } 384 385 void 386 yyerror(char *m) 387 { 388 pfmt(err, "rc: "); 389 if(runq->cmdfile) pfmt(err, "file %s: ", runq->cmdfile); 390 if(!runq->iflag) pfmt(err, "line %d: ", runq->lineno); 391 if(tok[0] && tok[0]!='\n') pfmt(err, "token %q: ", tok); 392 pfmt(err, "%s\n", m); 393 flush(err); 394 lastword=0; 395 lastdol=0; 396 while(lastc!='\n' && lastc!=EOF) advance(); 397 nerror++; 398 } 399