|
|
1.1 root 1: static char sccsid[] = "@(#)tk.c 2.6";
2:
3: #include <ctype.h>
4: #include "cdb.h"
5:
6: #define chTab '\t'
7: #define chSpace ' '
8: #define chUnder '_'
9: #define chDollar '$'
10: #define chBackSlash '\\'
11:
12: export int vcbTok, vcbPeek;
13: export TKE vtk, vtkPeek;
14: export char vsbTok[100], vsbTokPeek[100];
15: export LCE vlc; /* the current language which has precedence */
16:
17: #define icmdMax 20
18: int vicmdMac;
19: char *vrgCmd[icmdMax]; /* where we push command pointers */
20:
21: typedef struct { /* keyword */
22: char *sbKey;
23: short tk;
24: }
25: KWR, *pKWR;
26: #define cbKWR sizeof(KWR)
27: #define kwNil ((pKWR)0)
28:
29: KWR vrgKwCdb[] = {
30: "$in", tkInside,
31: };
32: #define ikwCdbMax (sizeof(vrgKwCdb)/cbKWR)
33:
34: KWR vrgKwC[] = {
35: "sizeof", tkSizeof,
36: };
37: #define ikwCMax (sizeof(vrgKwC)/cbKWR)
38:
39: KWR vrgKwFor[] = {
40: ".NE.", tkNotEqual,
41: ".EQ.", tkEqual,
42: ".LT.", tkLT,
43: ".LE.", tkLE,
44: ".GT.", tkGT,
45: ".GE.", tkGE,
46: };
47: #define ikwForMax (sizeof(vrgKwFor)/cbKWR)
48:
49: KWR vrgKwPas[] = {
50: "and", tkLAND,
51: "or", tkLOR,
52: "not", tkBang,
53: "div", tkDiv,
54: "mod", tkModulo,
55: };
56: #define ikwPasMax (sizeof(vrgKwPas)/cbKWR)
57:
58: #define isodigit(ch) (isdigit(ch) && (ch!='8') && (ch!='9'))
59:
60:
61: /* T K F K W */
62:
63: export void TkFKw(ptk, sbKey, rgKw, ikwMax)
64: TKE *ptk;
65: char *sbKey;
66: pKWR rgKw;
67: int ikwMax;
68: {
69: int i;
70: for (i=0; i < ikwMax; i++) {
71: if (FSbCmp(sbKey, rgKw[i].sbKey)) {
72: *ptk = rgKw[i].tk;
73: return;
74: }
75: }
76: } /* TkFKw */
77:
78:
79: /* C H F E S C A P E */
80:
81: local char ChFEscape(psbIn)
82: char **psbIn;
83: {
84: int i, val;
85: char ch;
86:
87: ch = **psbIn;
88: (*psbIn)++;
89: if (ch != chBackSlash)
90: return(ch); /* vanilla flavored char */
91: ch = **psbIn;
92: (*psbIn)++;
93: switch (ch) {
94: case 'b':
95: return('\b');
96: case 'f':
97: return('\f');
98: case 'n':
99: return('\n');
100: case 'r':
101: return('\r');
102: case 't':
103: return('\t');
104: case '\\':
105: return('\\');
106: case '\'':
107: return('\'');
108: case '0':
109: case '1':
110: case '2':
111: case '3':
112: case '4':
113: case '5':
114: case '6':
115: case '7':
116: /* it is an arbitrary 1-3 octal digit thingie */
117: val = 0;
118: for (i=0; i<3; i++) {
119: val = (val * 8) + (ch - '0');
120: ch = **psbIn; /* look at NEXT character */
121: if (!isodigit(ch))
122: break;
123: (*psbIn)++; /* is good digit, advance str pointer */
124: } /* for */
125: return(val);
126: } /* switch */
127: return(ch); /* by default we just ignore the backslash */
128: } /* ChFEscape */
129:
130:
131: /* T K F S T R */
132:
133: export TKE TkFStr(psbCmd, sbTok, pcb)
134: char **psbCmd, *sbTok;
135: int *pcb;
136: {
137: int i;
138: char ch, *sbCmd, *sbStart, sbT[10];
139: TKE tk;
140:
141: /* given a string, copy first token to safe place and advance string */
142:
143: sbCmd = *psbCmd;
144: if (sbCmd == sbNil)
145: return(tkNil);
146:
147: while (*sbCmd != chNull AND *sbCmd == chTab OR *sbCmd == chSpace)
148: sbCmd++; /* eat leading tabs and spaces */
149: if (*sbCmd == chNull) {
150: *pcb = 0;
151: sbTok[0] = chNull;
152: return(tkNil);
153: } /* if */
154:
155: sbStart = sbCmd; /* remember where we started */
156:
157: tk = tkNil;
158: ch = *sbCmd++;
159: if (isalpha(ch)
160: OR (ch == chUnder)
161: OR (ch == chDollar)) { /* string (var|command) token */
162: tk = tkStr;
163: while (isalnum(*sbCmd)
164: OR *sbCmd == chUnder)
165: sbCmd++;
166: }
167: else if (isdigit(ch)) { /* number */
168: tk = tkNumber;
169: if ((ch == '0') AND (*sbCmd == 'x')) {
170: sbCmd++; /* it's a hex number */
171: while (isxdigit(*sbCmd))
172: sbCmd++;
173: }
174: else {
175: while (isdigit(*sbCmd))
176: sbCmd++;
177: } /* if */
178: }
179: else if (ispunct(ch)) {
180: /* hopefully an interesting operator or something */
181: switch (ch) {
182: case '[':
183: tk = tkLSB;
184: break;
185: case ']':
186: tk = tkRSB;
187: break;
188: case '(':
189: tk = tkLP;
190: break;
191: case ')':
192: tk = tkRP;
193: break;
194: case '{':
195: tk = tkLCB;
196: break;
197: case '}':
198: tk = tkRCB;
199: break;
200: case '?':
201: tk = tkQuest;
202: break;
203: case '@':
204: tk = tkAt;
205: break;
206: case '$':
207: tk = tkDollar;
208: break;
209: case '#':
210: tk = tkHash;
211: break;
212: case ';':
213: tk = tkSemi;
214: break;
215: case ',':
216: tk = tkComma;
217: break;
218: case '_':
219: tk = tkUnderScore;
220: break;
221: case '\\':
222: tk = tkBackSlash;
223: break;
224: case '\'':
225: tk = tkCharConstant;
226: sbTok[0] = ChFEscape(&sbCmd);
227: if (*sbCmd != '\'')
228: UError("Character constant is missing ending '");
229: sbCmd++;
230: *pcb = 1;
231: goto special;
232: case '"':
233: tk = tkStrConstant;
234: i = 0;
235: while ((*sbCmd != chNull) AND (*sbCmd != '"')) {
236: sbTok[i] = ChFEscape(&sbCmd);
237: i++;
238: } /* while */
239: if (*sbCmd != '"')
240: UError("String constant is missing ending \"");
241: sbCmd++;
242: *pcb = i;
243: goto special;
244: case '.':
245: tk = tkDot;
246: if (vlc != lcFortran)
247: break;
248: if (sbCmd[2] == '.') {
249: /* we have '.XX.' - might be a relop */
250: strncpy(sbT, sbCmd-1, 4); /* get the whole thing */
251: TkFKw(&tk, sbT, vrgKwFor, ikwForMax);
252: if (tk != tkDot) {
253: /* we have a hit */
254: sbCmd += 3;
255: }
256: }
257: break;
258: case ':':
259: tk = tkColon;
260: if (*sbCmd == '=') {
261: sbCmd++;
262: tk = tkAssign;
263: } /* if */
264: break;
265: case '+':
266: tk = tkPlus;
267: if (*sbCmd == '=') {
268: sbCmd++;
269: tk = tkAssPlus;
270: } /* if */
271: break;
272: case '-':
273: tk = tkMinus;
274: if (*sbCmd == '>') {
275: sbCmd++;
276: tk = tkPtr;
277: }
278: else if (*sbCmd == '=') {
279: sbCmd++;
280: tk = tkAssMinus;
281: } /* if */
282: break;
283: case '*':
284: tk = tkStar;
285: if (*sbCmd == '=') {
286: sbCmd++;
287: tk = tkAssMult;
288: } /* if */
289: break;
290: case '/':
291: tk = tkSlash;
292: if (*sbCmd == '/') {
293: sbCmd++;
294: tk = tkDiv;
295: if (*sbCmd == '=') {
296: sbCmd++;
297: tk = tkAssDiv;
298: } /* if */
299: } /* if */
300: break;
301: case '%':
302: tk = tkModulo;
303: if (*sbCmd == '=') {
304: sbCmd++;
305: tk = tkAssMod;
306: } /* if */
307: break;
308: case '&':
309: tk = tkBitAnd;
310: if (*sbCmd == '&') {
311: sbCmd++;
312: tk = tkLAND;
313: }
314: else if (*sbCmd == '=') {
315: sbCmd++;
316: tk = tkAssBAND;
317: } /* if */
318: break;
319: case '|':
320: tk = tkBitOr;
321: if (*sbCmd == '|') {
322: sbCmd++;
323: tk = tkLOR;
324: }
325: else if (*sbCmd == '=') {
326: sbCmd++;
327: tk = tkAssBOR;
328: } /* if */
329: break;
330: case '^':
331: tk = tkXOR;
332: if (*sbCmd == '=') {
333: sbCmd++;
334: tk = tkAssXOR;
335: }
336: else if (*sbCmd == '.') {
337: if (vlc == lcPascal) {
338: sbCmd++;
339: tk = tkPtr;
340: }
341: } /* if */
342: break;
343: case '~':
344: tk = tkTilda;
345: break;
346: case '!':
347: tk = tkBang;
348: if (*sbCmd == '=') {
349: sbCmd++;
350: tk = tkNotEqual;
351: } /* if */
352: break;
353: case '=':
354: if (vlc == lcPascal) {
355: tk = tkEqual;
356: }
357: else {
358: tk = tkAssign;
359: if (*sbCmd == '=') {
360: sbCmd++;
361: tk = tkEqual;
362: } /* if */
363: }
364: break;
365: case '<':
366: tk = tkLT;
367: if (*sbCmd == '=') {
368: sbCmd++;
369: tk = tkLE;
370: }
371: else if (*sbCmd =='<') {
372: sbCmd++;
373: tk = tkLShift;
374: if (*sbCmd == '=') {
375: sbCmd++;
376: tk = tkAssLeft;
377: } /* if */
378: }
379: else if (*sbCmd == '>') {
380: sbCmd++;
381: tk = tkNotEqual;
382: } /* if */
383: break;
384: case '>':
385: tk = tkGT;
386: if (*sbCmd == '=') {
387: sbCmd++;
388: tk = tkGE;
389: }
390: else if (*sbCmd =='>') {
391: sbCmd++;
392: tk = tkRShift;
393: if (*sbCmd == '=') {
394: sbCmd++;
395: tk = tkAssRight;
396: } /* if */
397: } /* if */
398: break;
399: } /* switch */
400: }
401: else { /* it's <something else> !! */
402: tk = tkOther;
403: } /* if */
404:
405: *pcb = sbCmd - sbStart;
406: strncpy(sbTok, sbStart, *pcb);
407:
408: special: /* used by character and string constant routines */
409: sbTok[*pcb] = chNull;
410: *psbCmd = sbCmd;
411:
412: if (tk == tkStr) {
413: TkFKw(&tk, sbTok, vrgKwCdb, ikwCdbMax);
414: switch (vlc) {
415: case lcC:
416: TkFKw(&tk, sbTok, vrgKwC, ikwCMax);
417: break;
418: case lcPascal:
419: TkFKw(&tk, sbTok, vrgKwPas, ikwPasMax);
420: break;
421: case lcFortran:
422: TkFKw(&tk, sbTok, vrgKwFor, ikwForMax);
423: break;
424: } /* switch */
425: }
426:
427: return(tk);
428: } /* TkFStr */
429:
430:
431: /* P O P C M D */
432:
433: export char * PopCmd()
434: {
435: if (vicmdMac == 0)
436: return(sbNil);
437: return(vrgCmd[--vicmdMac]);
438: } /* PopCmd */
439:
440:
441: /* P U S H C M D */
442:
443: export void PushCmd(sbCmd)
444: char *sbCmd;
445: {
446: if (sbCmd == sbNil OR *sbCmd == chNull)
447: return;
448: if (vicmdMac >= icmdMax) {
449: vicmdMac = 0;
450: Panic("Too much command nesting - flushing everything");
451: } /* if */
452: vrgCmd[vicmdMac++] = sbCmd;
453: } /* PushCmd */
454:
455:
456: /* T K P E E K */
457:
458: export TKE TkPeek()
459: {
460: char *sbCmd;
461: /* used to peek at next token in global command line */
462: sbCmd = vsbCmd;
463: vtkPeek = TkFStr(&sbCmd, vsbTokPeek, &vcbPeek);
464: return(vtkPeek);
465: } /* TkPeek */
466:
467:
468: /* T K N E X T */
469:
470: export TKE TkNext()
471: {
472: /* used by most routines to eat next token in the global command line */
473: while ((vtk = TkFStr(&vsbCmd, vsbTok, &vcbTok)) == tkNil) {
474: if (vicmdMac == 0)
475: return(tkNil);
476: vsbCmd = PopCmd();
477: } /* while */
478: return(vtk);
479: } /* TkNext */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.