source: rtems/cpukit/httpd/ejlex.c @ cf1f72e

4.104.114.84.95
Last change on this file since cf1f72e was df49c60, checked in by Joel Sherrill <joel.sherrill@…>, on 06/12/00 at 15:00:15

Merged from 4.5.0-beta3a

  • Property mode set to 100644
File size: 13.2 KB
Line 
1/*
2 * ejlex.c -- Ejscript(TM) Lexical Analyser
3 *
4 * Copyright (c) Go Ahead Software, Inc., 1995-1999
5 *
6 * See the file "license.txt" for usage and redistribution license requirements
7 */
8
9/******************************** Description *********************************/
10
11/*
12 *      Ejscript lexical analyser. This implementes a lexical analyser for a
13 *      a subset of the JavaScript language.
14 */
15
16/********************************** Includes **********************************/
17
18#include        "ej.h"
19
20#if UEMF
21        #include "uemf.h"
22#else
23        #include "basic/basicInternal.h"
24#endif
25
26/****************************** Forward Declarations **************************/
27
28static int              getLexicalToken(ej_t* ep, int state);
29static int              tokenAddChar(ej_t *ep, int c);
30static int              inputGetc(ej_t* ep);
31static void             inputPutback(ej_t* ep, int c);
32
33/************************************* Code ***********************************/
34/*
35 *      Setup the lexical analyser
36 */
37
38int ejLexOpen(ej_t* ep)
39{
40        return 0;
41}
42
43/******************************************************************************/
44/*
45 *      Close the lexicial analyser
46 */
47
48void ejLexClose(ej_t* ep)
49{
50}
51
52/******************************************************************************/
53/*
54 *      Open a new input script
55 */
56
57int ejLexOpenScript(ej_t* ep, char_t *script)
58{
59        ejinput_t       *ip;
60
61        a_assert(ep);
62        a_assert(script);
63
64        if ((ep->input = balloc(B_L, sizeof(ejinput_t))) == NULL) {
65                return -1;
66        }
67        ip = ep->input;
68        memset(ip, 0, sizeof(*ip));
69
70        a_assert(ip);
71        a_assert(ip->putBackToken == NULL);
72        a_assert(ip->putBackTokenId == 0);
73
74/*
75 *      Create the parse token buffer and script buffer
76 */
77        if (ringqOpen(&ip->tokbuf, EJ_INC, -1) < 0) {
78                return -1;
79        }
80        if (ringqOpen(&ip->script, EJ_INC, -1) < 0) {
81                return -1;
82        }
83/*
84 *      Put the Ejscript into a ring queue for easy parsing
85 */
86        ringqPutstr(&ip->script, script);
87
88        ip->lineNumber = 1;
89        ip->lineLength = 0;
90        ip->lineColumn = 0;
91        ip->line = NULL;
92
93        return 0;
94}
95
96/******************************************************************************/
97/*
98 *      Close the input script
99 */
100
101void ejLexCloseScript(ej_t* ep)
102{
103        ejinput_t       *ip;
104
105        a_assert(ep);
106
107        ip = ep->input;
108        a_assert(ip);
109
110        if (ip->putBackToken) {
111                bfree(B_L, ip->putBackToken);
112                ip->putBackToken = NULL;
113        }
114        ip->putBackTokenId = 0;
115
116        if (ip->line) {
117                bfree(B_L, ip->line);
118                ip->line = NULL;
119        }
120
121        ringqClose(&ip->tokbuf);
122        ringqClose(&ip->script);
123
124        bfree(B_L, ip);
125}
126
127/******************************************************************************/
128/*
129 *      Save the input state
130 */
131
132void ejLexSaveInputState(ej_t* ep, ejinput_t* state)
133{
134        ejinput_t       *ip;
135
136        a_assert(ep);
137
138        ip = ep->input;
139        a_assert(ip);
140
141        *state = *ip;
142        if (ip->putBackToken) {
143                state->putBackToken = bstrdup(B_L, ip->putBackToken);
144        }
145}
146
147/******************************************************************************/
148/*
149 *      Restore the input state
150 */
151
152void ejLexRestoreInputState(ej_t* ep, ejinput_t* state)
153{
154        ejinput_t       *ip;
155
156        a_assert(ep);
157
158        ip = ep->input;
159        a_assert(ip);
160
161        ip->tokbuf = state->tokbuf;
162        ip->script = state->script;
163        ip->putBackTokenId = state->putBackTokenId;
164        if (ip->putBackToken) {
165                bfree(B_L, ip->putBackToken);
166        }
167        if (state->putBackToken) {
168                ip->putBackToken = bstrdup(B_L, state->putBackToken);
169        }
170}
171
172/******************************************************************************/
173/*
174 *      Free a saved input state
175 */
176
177void ejLexFreeInputState(ej_t* ep, ejinput_t* state)
178{
179        if (state->putBackToken) {
180                bfree(B_L, state->putBackToken);
181        }
182}
183
184/******************************************************************************/
185/*
186 *      Get the next Ejscript token
187 */
188
189int ejLexGetToken(ej_t* ep, int state)
190{
191        ep->tid = getLexicalToken(ep, state);
192        goahead_trace(7, T("ejGetToken: %d, \"%s\"\n"), ep->tid, ep->token);
193        return ep->tid;
194}
195
196/******************************************************************************/
197/*
198 *      Get the next Ejscript token
199 */
200
201static int getLexicalToken(ej_t* ep, int state)
202{
203        ringq_t         *inq, *tokq;
204        ejinput_t*      ip;
205        int                     done, tid, c, quote, style, back_quoted, lval, i;
206
207        a_assert(ep);
208        ip = ep->input;
209        a_assert(ip);
210
211        inq = &ip->script;
212        tokq = &ip->tokbuf;
213
214        ep->tid = -1;
215        tid = -1;
216        ep->token = T("");
217
218        ringqFlush(tokq);
219
220        if (ip->putBackTokenId > 0) {
221                ringqPutstr(tokq, ip->putBackToken);
222                tid = ip->putBackTokenId;
223                ip->putBackTokenId = 0;
224                ep->token = (char_t*) tokq->servp;
225                return tid;
226        }
227
228        if ((c = inputGetc(ep)) < 0) {
229                return TOK_EOF;
230        }
231
232        for (done = 0; !done; ) {
233                switch (c) {
234                case -1:
235                        return TOK_EOF;
236
237                case ' ':
238                case '\t':
239                case '\r':
240                        do {
241                                if ((c = inputGetc(ep)) < 0)
242                                        break;
243                        } while (c == ' ' || c == '\t' || c == '\r');
244                        break;
245
246                case '\n':
247                        return TOK_NEWLINE;
248
249                case '(':
250                        tokenAddChar(ep, c);
251                        return TOK_LPAREN;
252
253                case ')':
254                        tokenAddChar(ep, c);
255                        return TOK_RPAREN;
256
257                case '{':
258                        tokenAddChar(ep, c);
259                        return TOK_LBRACE;
260
261                case '}':
262                        tokenAddChar(ep, c);
263                        return TOK_RBRACE;
264
265                case '+':
266                        if ((c = inputGetc(ep)) < 0) {
267                                ejError(ep, T("Syntax Error"));
268                                return TOK_ERR;
269                        }
270                        if (c != '+' ) {
271                                inputPutback(ep, c);
272                                tokenAddChar(ep, EXPR_PLUS);
273                                return TOK_EXPR;
274                        }
275                        tokenAddChar(ep, EXPR_INC);
276                        return TOK_INC_DEC;
277
278                case '-':
279                        if ((c = inputGetc(ep)) < 0) {
280                                ejError(ep, T("Syntax Error"));
281                                return TOK_ERR;
282                        }
283                        if (c != '-' ) {
284                                inputPutback(ep, c);
285                                tokenAddChar(ep, EXPR_MINUS);
286                                return TOK_EXPR;
287                        }
288                        tokenAddChar(ep, EXPR_DEC);
289                        return TOK_INC_DEC;
290
291                case '*':
292                        tokenAddChar(ep, EXPR_MUL);
293                        return TOK_EXPR;
294
295                case '%':
296                        tokenAddChar(ep, EXPR_MOD);
297                        return TOK_EXPR;
298
299                case '/':
300/*
301 *                      Handle the division operator and comments
302 */
303                        if ((c = inputGetc(ep)) < 0) {
304                                ejError(ep, T("Syntax Error"));
305                                return TOK_ERR;
306                        }
307                        if (c != '*' && c != '/') {
308                                inputPutback(ep, c);
309                                tokenAddChar(ep, EXPR_DIV);
310                                return TOK_EXPR;
311                        }
312                        style = c;
313/*
314 *                      Eat comments. Both C and C++ comment styles are supported.
315 */
316                        while (1) {
317                                if ((c = inputGetc(ep)) < 0) {
318                                        ejError(ep, T("Syntax Error"));
319                                        return TOK_ERR;
320                                }
321                                if (c == '\n' && style == '/') {
322                                        break;
323                                } else if (c == '*') {
324                                        c = inputGetc(ep);
325                                        if (style == '/') {
326                                                if (c == '\n') {
327                                                        break;
328                                                }
329                                        } else {
330                                                if (c == '/') {
331                                                        break;
332                                                }
333                                        }
334                                }
335                        }
336/*
337 *                      Continue looking for a token, so get the next character
338 */
339                        if ((c = inputGetc(ep)) < 0) {
340                                return TOK_EOF;
341                        }
342                        break;
343
344                case '<':                                                                       /* < and <= */
345                        if ((c = inputGetc(ep)) < 0) {
346                                ejError(ep, T("Syntax Error"));
347                                return TOK_ERR;
348                        }
349                        if (c == '<') {
350                                tokenAddChar(ep, EXPR_LSHIFT);
351                                return TOK_EXPR;
352                        } else if (c == '=') {
353                                tokenAddChar(ep, EXPR_LESSEQ);
354                                return TOK_EXPR;
355                        }
356                        tokenAddChar(ep, EXPR_LESS);
357                        inputPutback(ep, c);
358                        return TOK_EXPR;
359
360                case '>':                                                                       /* > and >= */
361                        if ((c = inputGetc(ep)) < 0) {
362                                ejError(ep, T("Syntax Error"));
363                                return TOK_ERR;
364                        }
365                        if (c == '>') {
366                                tokenAddChar(ep, EXPR_RSHIFT);
367                                return TOK_EXPR;
368                        } else if (c == '=') {
369                                tokenAddChar(ep, EXPR_GREATEREQ);
370                                return TOK_EXPR;
371                        }
372                        tokenAddChar(ep, EXPR_GREATER);
373                        inputPutback(ep, c);
374                        return TOK_EXPR;
375
376                case '=':                                                                       /* "==" */
377                        if ((c = inputGetc(ep)) < 0) {
378                                ejError(ep, T("Syntax Error"));
379                                return TOK_ERR;
380                        }
381                        if (c == '=') {
382                                tokenAddChar(ep, EXPR_EQ);
383                                return TOK_EXPR;
384                        }
385                        inputPutback(ep, c);
386                        return TOK_ASSIGNMENT;
387
388                case '!':                                                                       /* "!=" */
389                        if ((c = inputGetc(ep)) < 0) {
390                                ejError(ep, T("Syntax Error"));
391                                return TOK_ERR;
392                        }
393                        if (c == '=') {
394                                tokenAddChar(ep, EXPR_NOTEQ);
395                                return TOK_EXPR;
396                        }
397                        tokenAddChar(ep, COND_NOT);
398                        return TOK_LOGICAL;
399
400                case ';':
401                        tokenAddChar(ep, c);
402                        return TOK_SEMI;
403
404                case ',':
405                        tokenAddChar(ep, c);
406                        return TOK_COMMA;
407
408                case '|':                                                                       /* "||" */
409                        if ((c = inputGetc(ep)) < 0 || c != '|') {
410                                ejError(ep, T("Syntax Error"));
411                                return TOK_ERR;
412                        }
413                        tokenAddChar(ep, COND_OR);
414                        return TOK_LOGICAL;
415
416                case '&':                                                                       /* "&&" */
417                        if ((c = inputGetc(ep)) < 0 || c != '&') {
418                                ejError(ep, T("Syntax Error"));
419                                return TOK_ERR;
420                        }
421                        tokenAddChar(ep, COND_AND);
422                        return TOK_LOGICAL;
423
424                case '\"':                                                                      /* String quote */
425                case '\'':
426                        quote = c;
427                        if ((c = inputGetc(ep)) < 0) {
428                                ejError(ep, T("Syntax Error"));
429                                return TOK_ERR;
430                        }
431                        back_quoted = 0;
432                        while (c != quote) {
433                                if (c == '\\' && !back_quoted) {
434                                        back_quoted++;
435                                } else if (back_quoted) {
436                                        if (gisdigit((char_t) c)) {
437                                                lval = 0;
438                                                for (i = 0; i < 3; i++) {
439                                                        if ('0' <= c && c <= '7') {
440                                                                break;
441                                                        }
442                                                        lval = lval * 8 + c;
443                                                        if ((c = inputGetc(ep)) < 0) {
444                                                                break;
445                                                        }
446                                                }
447                                                c = (int) lval;
448
449                                        } else if (back_quoted) {
450                                                switch (c) {
451                                                case 'n':
452                                                        c = '\n'; break;
453                                                case 'b':
454                                                        c = '\b'; break;
455                                                case 'f':
456                                                        c = '\f'; break;
457                                                case 'r':
458                                                        c = '\r'; break;
459                                                case 't':
460                                                        c = '\t'; break;
461                                                case 'x':
462                                                        lval = 0;
463                                                        for (i = 0; i < 2; i++) {
464                                                                if (! gisxdigit((char_t) c)) {
465                                                                        break;
466                                                                }
467                                                                lval = lval * 16 + c;
468                                                                if ((c = inputGetc(ep)) < 0) {
469                                                                        break;
470                                                                }
471                                                        }
472                                                        c = (int) lval;
473                                                        break;
474                                                case 'u':
475                                                        lval = 0;
476                                                        for (i = 0; i < 4; i++) {
477                                                                if (! gisxdigit((char_t) c)) {
478                                                                        break;
479                                                                }
480                                                                lval = lval * 16 + c;
481                                                                if ((c = inputGetc(ep)) < 0) {
482                                                                        break;
483                                                                }
484                                                        }
485                                                        c = (int) lval;
486                                                        break;
487                                                case '\'':
488                                                case '\"':
489                                                        break;
490                                                }
491                                        }
492                                        back_quoted = 0;
493                                        if (tokenAddChar(ep, c) < 0) {
494                                                return TOK_ERR;
495                                        }
496                                } else {
497                                        if (tokenAddChar(ep, c) < 0) {
498                                                return TOK_ERR;
499                                        }
500                                }
501                                if ((c = inputGetc(ep)) < 0) {
502                                        ejError(ep, T("Unmatched Quote"));
503                                        return TOK_ERR;
504                                }
505                        }
506                        return TOK_LITERAL;
507
508                case '0': case '1': case '2': case '3': case '4':
509                case '5': case '6': case '7': case '8': case '9':
510                        do {
511                                if (tokenAddChar(ep, c) < 0) {
512                                        return TOK_ERR;
513                                }
514                                if ((c = inputGetc(ep)) < 0)
515                                        break;
516                        } while (gisdigit((char_t) c));
517                        inputPutback(ep, c);
518                        return TOK_LITERAL;
519
520                default:
521/*
522 *                      Identifiers or a function names
523 */
524                        back_quoted = 0;
525                        while (1) {
526                                if (c == '\\' && !back_quoted) {
527                                        back_quoted++;
528                                } else {
529                                        back_quoted = 0;
530                                        if (tokenAddChar(ep, c) < 0) {
531                                                break;
532                                        }
533                                }
534                                if ((c = inputGetc(ep)) < 0) {
535                                        break;
536                                }
537                                if (!back_quoted && (!gisalnum((char_t) c) && c != '$' &&
538                                                c != '_')) {
539                                        break;
540                                }
541                        }
542                        if (! gisalpha(*tokq->servp) && *tokq->servp != '$' &&
543                                        *tokq->servp != '_') {
544                                ejError(ep, T("Invalid identifier %s"), tokq->servp);
545                                return TOK_ERR;
546                        }
547/*
548 *                      Check for reserved words (only "if", "else", "var", "for"
549 *                      and "return" at the moment)
550 */
551                        if (state == STATE_STMT) {
552                                if (gstrcmp(ep->token, T("if")) == 0) {
553                                        return TOK_IF;
554                                } else if (gstrcmp(ep->token, T("else")) == 0) {
555                                        return TOK_ELSE;
556                                } else if (gstrcmp(ep->token, T("var")) == 0) {
557                                        return TOK_VAR;
558                                } else if (gstrcmp(ep->token, T("for")) == 0) {
559                                        return TOK_FOR;
560                                } else if (gstrcmp(ep->token, T("return")) == 0) {
561                                        return TOK_RETURN;
562                                }
563                        }
564
565/*
566 *                      skip white space after token to find out whether this is
567 *                      a function or not.
568 */
569                        while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
570                                if ((c = inputGetc(ep)) < 0)
571                                        break;
572                        }
573
574                        tid = (c == '(') ? TOK_FUNCTION : TOK_ID;
575                        done++;
576                }
577        }
578
579/*
580 *      Putback the last extra character for next time
581 */
582        inputPutback(ep, c);
583        return tid;
584}
585
586/******************************************************************************/
587/*
588 *      Putback the last token read
589 */
590
591void ejLexPutbackToken(ej_t* ep, int tid, char_t *string)
592{
593        ejinput_t*      ip;
594
595        a_assert(ep);
596        ip = ep->input;
597        a_assert(ip);
598
599        if (ip->putBackToken) {
600                bfree(B_L, ip->putBackToken);
601        }
602        ip->putBackTokenId = tid;
603        ip->putBackToken = bstrdup(B_L, string);
604}
605
606/******************************************************************************/
607/*
608 *      Add a character to the token ringq buffer
609 */
610
611static int tokenAddChar(ej_t *ep, int c)
612{
613        ejinput_t*      ip;
614
615        a_assert(ep);
616        ip = ep->input;
617        a_assert(ip);
618
619        if (ringqPutc(&ip->tokbuf, (char_t) c) < 0) {
620                ejError(ep, T("Token too big"));
621                return -1;
622        }
623        * ((char_t*) ip->tokbuf.endp) = '\0';
624        ep->token = (char_t*) ip->tokbuf.servp;
625
626        return 0;
627}
628
629/******************************************************************************/
630/*
631 *      Get another input character
632 */
633
634static int inputGetc(ej_t* ep)
635{
636        ejinput_t       *ip;
637        int                     c, len;
638
639        a_assert(ep);
640        ip = ep->input;
641
642        if ((len = ringqLen(&ip->script)) == 0) {
643                return -1;
644        }
645
646        c = ringqGetc(&ip->script);
647
648        if (c == '\n') {
649                ip->lineNumber++;
650                ip->lineColumn = 0;
651        } else {
652                if ((ip->lineColumn + 2) >= ip->lineLength) {
653                        ip->lineLength += EJ_INC;
654                        ip->line = brealloc(B_L, ip->line, ip->lineLength * sizeof(char_t));
655                }
656                ip->line[ip->lineColumn++] = c;
657                ip->line[ip->lineColumn] = '\0';
658        }
659        return c;
660}
661
662/******************************************************************************/
663/*
664 *      Putback a character onto the input queue
665 */
666
667static void inputPutback(ej_t* ep, int c)
668{
669        ejinput_t       *ip;
670
671        a_assert(ep);
672
673        ip = ep->input;
674        ringqInsertc(&ip->script, (char_t) c);
675        ip->lineColumn--;
676        ip->line[ip->lineColumn] = '\0';
677}
678
679/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.