Blob


1 #include "rc.h"
2 #include "exec.h"
3 #include "io.h"
4 #include "getflags.h"
5 #include "fns.h"
6 int getnext(void);
7 int wordchr(int c)
8 {
9 return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
10 }
11 int idchr(int c)
12 {
13 /*
14 * Formerly:
15 * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
16 * || c=='_' || c=='*';
17 */
18 return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
19 }
20 int future=EOF;
21 int doprompt=1;
22 int inquote;
23 /*
24 * Look ahead in the input stream
25 */
26 int nextc(void){
27 if(future==EOF) future=getnext();
28 return future;
29 }
30 /*
31 * Consume the lookahead character.
32 */
33 int advance(void){
34 int c=nextc();
35 lastc=future;
36 future=EOF;
37 return c;
38 }
39 /*
40 * read a character from the input stream
41 */
42 int getnext(void){
43 register int c;
44 static int peekc=EOF;
45 if(peekc!=EOF){
46 c=peekc;
47 peekc=EOF;
48 return c;
49 }
50 if(runq->eof) return EOF;
51 if(doprompt) pprompt();
52 c=rchr(runq->cmdfd);
53 if(!inquote && c=='\\'){
54 c=rchr(runq->cmdfd);
55 if(c=='\n'){
56 doprompt=1;
57 c=' ';
58 }
59 else{
60 peekc=c;
61 c='\\';
62 }
63 }
64 doprompt=doprompt || c=='\n' || c==EOF;
65 if(c==EOF) runq->eof++;
66 else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
67 return c;
68 }
69 void pprompt(void){
70 var *prompt;
71 if(runq->iflag){
72 pstr(err, promptstr);
73 flush(err);
74 prompt=vlook("prompt");
75 if(prompt->val && prompt->val->next)
76 promptstr=prompt->val->next->word;
77 else
78 promptstr="\t";
79 }
80 runq->lineno++;
81 doprompt=0;
82 }
83 void skipwhite(void){
84 int c;
85 for(;;){
86 c=nextc();
87 if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */
88 for(;;){
89 c=nextc();
90 if(c=='\n' || c==EOF) break;
91 advance();
92 }
93 }
94 if(c==' ' || c=='\t') advance();
95 else return;
96 }
97 }
98 void skipnl(void){
99 register int c;
100 for(;;){
101 skipwhite();
102 c=nextc();
103 if(c!='\n') return;
104 advance();
107 int nextis(int c){
108 if(nextc()==c){
109 advance();
110 return 1;
112 return 0;
114 char *addtok(char *p, int val){
115 if(p==0) return 0;
116 if(p==&tok[NTOK-1]){
117 *p=0;
118 yyerror("token buffer too short");
119 return 0;
121 *p++=val;
122 return p;
124 char *addutf(char *p, int c){
125 p=addtok(p, c);
126 if(twobyte(c)) /* 2-byte escape */
127 return addtok(p, advance());
128 if(threebyte(c)){ /* 3-byte escape */
129 p=addtok(p, advance());
130 return addtok(p, advance());
132 return p;
134 int lastdol; /* was the last token read '$' or '$#' or '"'? */
135 int lastword; /* was the last token read a word or compound word terminator? */
136 int yylex(void){
137 register int c, d=nextc();
138 register char *w=tok;
139 register struct tree *t;
140 yylval.tree=0;
141 /*
142 * Embarassing sneakiness: if the last token read was a quoted or unquoted
143 * WORD then we alter the meaning of what follows. If the next character
144 * is `(', we return SUB (a subscript paren) and consume the `('. Otherwise,
145 * if the next character is the first character of a simple or compound word,
146 * we insert a `^' before it.
147 */
148 if(lastword){
149 lastword=0;
150 if(d=='('){
151 advance();
152 strcpy(tok, "( [SUB]");
153 return SUB;
155 if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
156 strcpy(tok, "^");
157 return '^';
160 inquote=0;
161 skipwhite();
162 switch(c=advance()){
163 case EOF:
164 lastdol=0;
165 strcpy(tok, "EOF");
166 return EOF;
167 case '$':
168 lastdol=1;
169 if(nextis('#')){
170 strcpy(tok, "$#");
171 return COUNT;
173 if(nextis('"')){
174 strcpy(tok, "$\"");
175 return '"';
177 strcpy(tok, "$");
178 return '$';
179 case '&':
180 lastdol=0;
181 if(nextis('&')){
182 skipnl();
183 strcpy(tok, "&&");
184 return ANDAND;
186 strcpy(tok, "&");
187 return '&';
188 case '|':
189 lastdol=0;
190 if(nextis(c)){
191 skipnl();
192 strcpy(tok, "||");
193 return OROR;
195 case '<':
196 case '>':
197 lastdol=0;
198 /*
199 * funny redirection tokens:
200 * redir: arrow | arrow '[' fd ']'
201 * arrow: '<' | '<<' | '>' | '>>' | '|'
202 * fd: digit | digit '=' | digit '=' digit
203 * digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
204 * some possibilities are nonsensical and get a message.
205 */
206 *w++=c;
207 t=newtree();
208 switch(c){
209 case '|':
210 t->type=PIPE;
211 t->fd0=1;
212 t->fd1=0;
213 break;
214 case '>':
215 t->type=REDIR;
216 if(nextis(c)){
217 t->rtype=APPEND;
218 *w++=c;
220 else t->rtype=WRITE;
221 t->fd0=1;
222 break;
223 case '<':
224 t->type=REDIR;
225 if(nextis(c)){
226 t->rtype=HERE;
227 *w++=c;
229 else t->rtype=READ;
230 t->fd0=0;
231 break;
233 if(nextis('[')){
234 *w++='[';
235 c=advance();
236 if(c<'0' || '9'<c){
237 RedirErr:
238 *w++ = c;
239 *w=0;
240 yyerror(t->type==PIPE?"pipe syntax"
241 :"redirection syntax");
242 return EOF;
244 t->fd0=0;
245 do{
246 t->fd0=t->fd0*10+c-'0';
247 *w++=c;
248 c=advance();
249 }while('0'<=c && c<='9');
250 if(c=='='){
251 *w++='=';
252 if(t->type==REDIR) t->type=DUP;
253 c=advance();
254 if('0'<=c && c<='9'){
255 t->rtype=DUPFD;
256 t->fd1=t->fd0;
257 t->fd0=0;
258 do{
259 t->fd0=t->fd0*10+c-'0';
260 *w++=c;
261 c=advance();
262 }while('0'<=c && c<='9');
264 else{
265 if(t->type==PIPE) goto RedirErr;
266 t->rtype=CLOSE;
269 *w=0;
270 if(c!=']'
271 || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
272 goto RedirErr;
273 *w++=']';
275 *w='\0';
276 yylval.tree=t;
277 if(t->type==PIPE) skipnl();
278 return t->type;
279 case '\'':
280 lastdol=0;
281 lastword=1;
282 inquote=1;
283 for(;;){
284 c=advance();
285 if(c==EOF) break;
286 if(c=='\''){
287 if(nextc()!='\'')
288 break;
289 advance();
291 w=addutf(w, c);
293 if(w!=0) *w='\0';
294 t=token(tok, WORD);
295 t->quoted=1;
296 yylval.tree=t;
297 return t->type;
299 if(!wordchr(c)){
300 lastdol=0;
301 tok[0]=c;
302 tok[1]='\0';
303 return c;
305 for(;;){
306 /* next line should have (char)c==GLOB, but ken's compiler is broken */
307 if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
308 w=addtok(w, GLOB);
309 w=addutf(w, c);
310 c=nextc();
311 if(lastdol?!idchr(c):!wordchr(c)) break;
312 advance();
315 lastword=1;
316 lastdol=0;
317 if(w!=0) *w='\0';
318 t=klook(tok);
319 if(t->type!=WORD) lastword=0;
320 t->quoted=0;
321 yylval.tree=t;
322 return t->type;