Logo Search packages:      
Sourcecode: ksh version File versions

extoken.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1989-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * expression library default lexical analyzer
 */

#include "exlib.h"

#if !defined(TRACE_lex) && _BLD_DEBUG
#define TRACE_lex -10
#endif

#if TRACE_lex

/*
 * trace c for op
 */

static void
trace(Expr_t* ex, int lev, char* op, int c)
{
      char* s;
      char* t;
      char  buf[16];

      t = "";
      switch (c)
      {
      case 0:
            s = " EOF";
            break;
      case '=':
            s = t = buf;
            *t++ = ' ';
            if (!lev && exlval.op != c)
                  *t++ = exlval.op;
            *t++ = c;
            *t = 0;
            break;
      case AND:
            s = " AND ";
            t = "&&";
            break;
      case DEC:
            s = " DEC ";
            t = "--";
            break;
      case DECLARE:
            s = " DECLARE ";
            t = exlval.id->name;
            break;
      case DYNAMIC:
            s = " DYNAMIC ";
            t = exlval.id->name;
            break;
      case EQ:
            s = " EQ ";
            t = "==";
            break;
      case FLOATING:
            s = " FLOATING ";
            sfsprintf(t = buf, sizeof(buf), "%f", exlval.floating);
            break;
      case GE:
            s = " GE ";
            t = ">=";
            break;
      case ID:
            s = " ID ";
            t = exlval.id->name;
            break;
      case INC:
            s = "INC ";
            t = "++";
            break;
      case INTEGER:
            s = " INTEGER ";
            sfsprintf(t = buf, sizeof(buf), "%I*d", sizeof(exlval.integer), exlval.integer);
            break;
      case LABEL:
            s = " LABEL ";
            t = exlval.id->name;
            break;
      case LE:
            s = " LE ";
            t = "<=";
            break;
      case LS:
            s = " LS ";
            t = "<<";
            break;
      case NAME:
            s = " NAME ";
            t = exlval.id->name;
            break;
      case NE:
            s = " NE ";
            t = "!=";
            break;
      case OR:
            s = " OR ";
            t = "||";
            break;
      case RS:
            s = " RS ";
            t = ">>";
            break;
      case STRING:
            s = " STRING ";
            t = fmtesc(exlval.string);
            break;
      case UNSIGNED:
            s = " UNSIGNED ";
            sfsprintf(t = buf, sizeof(buf), "%I*u", sizeof(exlval.integer), exlval.integer);
            break;
      case BREAK:
            s = " break";
            break;
      case CASE:
            s = " case";
            break;
      case CONTINUE:
            s = " continue";
            break;
      case DEFAULT:
            s = " default";
            break;
      case ELSE:
            s = " else";
            break;
      case EXIT:
            s = " exit";
            break;
      case FOR:
            s = " for";
            break;
      case IF:
            s = " if";
            break;
      case PRAGMA:
            s = " pragma";
            break;
      case PRINTF:
            s = " printf";
            break;
      case QUERY:
            s = " query";
            break;
      case RETURN:
            s = " return";
            break;
      case SPRINTF:
            s = " sprintf";
            break;
      case SWITCH:
            s = " switch";
            break;
      case WHILE:
            s = " while";
            break;
      default:
            if (c < 0177)
            {
                  s = buf;
                  *s++ = c;
                  *s = 0;
                  t = fmtesc(buf);
                  s = " ";
            }
            break;
      }
      error(TRACE_lex + lev, "%s: [%d] %04d%s%s", op, ex->input->nesting, c, s, t);
}

/*
 * trace wrapper for extoken()
 */

extern int  _extoken_(Expr_t*);

int
extoken(Expr_t* ex)
{
      int   c;

#define extoken   _extoken_

      c = extoken(ex);
      trace(ex, 0, "exlex", c);
      return c;
}

#else

#define trace(p,a,b,c)

#endif

/*
 * get the next expression char
 */

static int
lex(register Expr_t* ex)
{
      register int      c;

      for (;;)
      {
            if (c = ex->input->peek)
                  ex->input->peek = 0;
            else if (ex->input->pp)
            {
                  if (!(c = *ex->input->pp++))
                  {
                        ex->input->pp = 0;
                        continue;
                  }
            }
            else if (ex->input->sp)
            {
                  if (!(c = *ex->input->sp++))
                  {
                        if (!expop(ex))
                              continue;
                        else trace(ex, -1, "expop sp FAIL", 0);
                        ex->input->sp--;
                  }
            }
            else if (ex->input->fp)
            {
                  if ((c = sfgetc(ex->input->fp)) == EOF)
                  {
                        if (!expop(ex))
                              continue;
                        else trace(ex, -1, "expop fp FAIL", 0);
                        c = 0;
                  }
                  else if ((ex->disc->flags & EX_INTERACTIVE) && c == '\n' && ex->input->next && !ex->input->next->next && ex->input->nesting <= 0)
                  {
                        error_info.line++;
                        expop(ex);
                        trace(ex, -1, "expop sp FORCE", 0);
                        c = 0;
                  }
            }
            else c = 0;
            if (c == '\n')
                  setcontext(ex);
            else if (c)
                  putcontext(ex, c);
            trace(ex, -3, "ex--lex", c);
            return c;
      }
}

/*
 * get the next expression token
 */

int
extoken(register Expr_t* ex)
{
      register int      c;
      register char*    s;
      register int      q;
      int         b;
      char*       e;

      if (ex->eof || ex->errors)
            return 0;
 again:
      for (;;) switch (c = lex(ex))
      {
      case 0:
            goto eof;
      case '/':
            switch (q = lex(ex))
            {
            case '*':
                  for (;;) switch (lex(ex))
                  {
                  case '\n':
                        if (error_info.line)
                              error_info.line++;
                        else error_info.line = 2;
                        continue;
                  case '*':
                        switch (lex(ex))
                        {
                        case 0:
                              goto eof;
                        case '\n':
                              if (error_info.line)
                                    error_info.line++;
                              else error_info.line = 2;
                              break;
                        case '*':
                              exunlex(ex, '*');
                              break;
                        case '/':
                              goto again;
                        }
                        break;
                  }
                  break;
            case '/':
                  while ((c = lex(ex)) != '\n')
                        if (!c)
                              goto eof;
                  break;
            default:
                  goto opeq;
            }
            /*FALLTHROUGH*/
      case '\n':
            if (error_info.line)
                  error_info.line++;
            else error_info.line = 2;
            /*FALLTHROUGH*/
      case ' ':
      case '\t':
            break;
      case '(':
      case '{':
      case '[':
            ex->input->nesting++;
            return exlval.op = c;
      case ')':
      case '}':
      case ']':
            ex->input->nesting--;
            return exlval.op = c;
      case '+':
      case '-':
            if ((q = lex(ex)) == c)
                  return exlval.op = c == '+' ? INC : DEC;
            goto opeq;
      case '*':
      case '%':
      case '^':
            q = lex(ex);
      opeq:
            exlval.op = c;
            if (q == '=')
                  c = '=';
            else if (q == '%' && c == '%')
            {
                  if (ex->input->fp)
                        ex->more = (const char*)ex->input->fp;
                  else ex->more = ex->input->sp;
                  goto eof;
            }
            else exunlex(ex, q);
            return c;
      case '&':
      case '|':
            if ((q = lex(ex)) == '=')
            {
                  exlval.op = c;
                  return '=';
            }
            if (q == c)
                  c = c == '&' ? AND : OR;
            else exunlex(ex, q);
            return exlval.op = c;
      case '<':
      case '>':
            if ((q = lex(ex)) == c)
            {
                  exlval.op = c = c == '<' ? LS : RS;
                  if ((q = lex(ex)) == '=')
                        c = '=';
                  else exunlex(ex, q);
                  return c;
            }
            goto relational;
      case '=':
      case '!':
            q = lex(ex);
      relational:
            if (q == '=') switch (c)
            {
            case '<':
                  c = LE;
                  break;
            case '>':
                  c = GE;
                  break;
            case '=':
                  c = EQ;
                  break;
            case '!':
                  c = NE;
                  break;
            }
            else exunlex(ex, q);
            return exlval.op = c;
      case '#':
            if (!ex->linewrap && !(ex->disc->flags & EX_PURE))
            {
                  s = ex->linep - 1;
                  while (s > ex->line && isspace(*(s - 1)))
                        s--;
                  if (s == ex->line)
                  {
                        switch (extoken(ex))
                        {
                        case DYNAMIC:
                        case ID:
                        case NAME:
                              s = exlval.id->name;
                              break;
                        default:
                              s = "";
                              break;
                        }
                        if (streq(s, "include"))
                        {
                              if (extoken(ex) != STRING)
                                    exerror("#%s: string argument expected", s);
                              else if (!expush(ex, exlval.string, 1, NiL, NiL))
                              {
                                    setcontext(ex);
                                    goto again;
                              }
                        }
                        else exerror("unknown directive");
                  }
            }
            return exlval.op = c;
      case '\'':
      case '"':
            q = c;
            sfstrseek(ex->tmp, 0, SEEK_SET);
            ex->input->nesting++;
            while ((c = lex(ex)) != q)
            {
                  if (c == '\\')
                  {
                        sfputc(ex->tmp, c);
                        c = lex(ex);
                  }
                  if (!c)
                  {
                        exerror("unterminated %c string", q);
                        goto eof;
                  }
                  if (c == '\n')
                  {
                        if (error_info.line)
                              error_info.line++;
                        else error_info.line = 2;
                  }
                  sfputc(ex->tmp, c);
            }
            ex->input->nesting--;
            s = exstash(ex->tmp, NiL);
            if (q == '"' || (ex->disc->flags & EX_CHARSTRING))
            {
                  if (!(exlval.string = vmstrdup(ex->vm, s)))
                        goto eof;
                  stresc(exlval.string);
                  return STRING;
            }
            exlval.integer = chrtoi(s);
            return INTEGER;
      case '.':
            if (isdigit(c = lex(ex)))
            {
                  sfstrseek(ex->tmp, 0, SEEK_SET);
                  sfputc(ex->tmp, '0');
                  sfputc(ex->tmp, '.');
                  goto floating;
            }
            exunlex(ex, c);
            return exlval.op = '.';
      case '0': case '1': case '2': case '3': case '4':
      case '5': case '6': case '7': case '8': case '9':
            sfstrseek(ex->tmp, 0, SEEK_SET);
            sfputc(ex->tmp, c);
            q = INTEGER;
            b = 0;
            if ((c = lex(ex)) == 'x' || c == 'X')
            {
                  b = 16;
                  sfputc(ex->tmp, c);
                  for (;;)
                  {
                        switch (c = lex(ex))
                        {
                        case '0': case '1': case '2': case '3': case '4':
                        case '5': case '6': case '7': case '8': case '9':
                        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 
                        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 
                              sfputc(ex->tmp, c);
                              continue;
                        }
                        break;
                  }
            }
            else
            {
                  while (isdigit(c))
                  {
                        sfputc(ex->tmp, c);
                        c = lex(ex);
                  }
                  if (c == '#')
                  {
                        s = exstash(ex->tmp, NiL);
                        b = strtol(s, NiL, 10);
                        do
                        {
                              sfputc(ex->tmp, c);
                        } while (isalnum(c = lex(ex)));
                  }
                  else
                  {
                        if (c == '.')
                        {
                        floating:
                              q = FLOATING;
                              sfputc(ex->tmp, c);
                              while (isdigit(c = lex(ex)))
                                    sfputc(ex->tmp, c);
                        }
                        if (c == 'e' || c == 'E')
                        {
                              q = FLOATING;
                              sfputc(ex->tmp, c);
                              if ((c = lex(ex)) == '-' || c == '+')
                              {
                                    sfputc(ex->tmp, c);
                                    c = lex(ex);
                              }
                              while (isdigit(c))
                              {
                                    sfputc(ex->tmp, c);
                                    c = lex(ex);
                              }
                        }
                  }
            }
            s = exstash(ex->tmp, NiL);
            if (q == FLOATING)
                  exlval.floating = strtod(s, &e);
            else
            {
                  if (c == 'u' || c == 'U')
                  {
                        q = UNSIGNED;
                        c = lex(ex);
                        exlval.integer = strtoull(s, &e, b);
                  }
                  else
                        exlval.integer = strtoll(s, &e, b);
                  if (*e)
                  {
                        *--e = 1;
                        exlval.integer *= strton(e, &e, NiL, 0);
                  }
            }
            exunlex(ex, c);
            if (*e || isalpha(c) || c == '_' || c == '$')
            {
                  exerror("%s: invalid numeric constant", s);
                  goto eof;
            }
            return q;
      default:
            if (isalpha(c) || c == '_' || c == '$')
            {
                  sfstrseek(ex->tmp, 0, SEEK_SET);
                  sfputc(ex->tmp, c);
                  while (isalnum(c = lex(ex)) || c == '_' || c == '$')
                        sfputc(ex->tmp, c);
                  exunlex(ex, c);
                  s = exstash(ex->tmp, NiL);
                  if (!(exlval.id = (Exid_t*)dtmatch(ex->symbols, s)))
                  {
                        if (!(exlval.id = newof(0, Exid_t, 1, strlen(s) - EX_NAMELEN + 1)))
                        {
                              exnospace();
                              goto eof;
                        }
                        strcpy(exlval.id->name, s);
                        exlval.id->lex = NAME;
                        dtinsert((ex->formals || !ex->symbols->view) ? ex->symbols : ex->symbols->view, exlval.id);
                  }

                  /*
                   * lexical analyzer state controlled by the grammar
                   */

                  switch (exlval.id->lex)
                  {
                  case DECLARE:
                        if (exlval.id->index == CHAR)
                        {
                              /*
                               * `char*' === `string'
                               * the * must immediately follow char
                               */

                              if (c == '*')
                              {
                                    lex(ex);
                                    exlval.id = id_string;
                              }
                        }
                        break;
                  case NAME:
                        /*
                         * action labels are disambiguated from ?:
                         * through the expr.nolabel grammar hook
                         * the : must immediately follow labels
                         */

                        if (c == ':' && !expr.nolabel)
                              return LABEL;
                        break;
                  case PRAGMA:
                        /*
                         * user specific statement stripped and
                         * passed as string
                         */

                        {
                              int   b;
                              int   n;
                              int   pc;
                              int   po;
                              int   t;

                              /*UNDENT...*/
      sfstrseek(ex->tmp, 0, SEEK_SET);
      b = 1;
      n = 0;
      po = 0;
      t = 0;
      for (c = t = lex(ex);; c = lex(ex))
      {
            switch (c)
            {
            case 0:
                  goto eof;
            case '/':
                  switch (q = lex(ex))
                  {
                  case '*':
                        for (;;)
                        {
                              switch (lex(ex))
                              {
                              case '\n':
                                    if (error_info.line)
                                          error_info.line++;
                                    else error_info.line = 2;
                                    continue;
                              case '*':
                                    switch (lex(ex))
                                    {
                                    case 0:
                                          goto eof;
                                    case '\n':
                                          if (error_info.line)
                                                error_info.line++;
                                          else error_info.line = 2;
                                          continue;
                                    case '*':
                                          exunlex(ex, '*');
                                          continue;
                                    case '/':
                                          break;
                                    default:
                                          continue;
                                    }
                                    break;
                              }
                              if (!b++)
                                    goto eof;
                              sfputc(ex->tmp, ' ');
                              break;
                        }
                        break;
                  case '/':
                        while ((c = lex(ex)) != '\n')
                              if (!c)
                                    goto eof;
                        if (error_info.line)
                              error_info.line++;
                        else error_info.line = 2;
                        b = 1;
                        sfputc(ex->tmp, '\n');
                        break;
                  default:
                        b = 0;
                        sfputc(ex->tmp, c);
                        sfputc(ex->tmp, q);
                        break;
                  }
                  continue;
            case '\n':
                  if (error_info.line)
                        error_info.line++;
                  else error_info.line = 2;
                  b = 1;
                  sfputc(ex->tmp, '\n');
                  continue;
            case ' ':
            case '\t':
                  if (!b++)
                        goto eof;
                  sfputc(ex->tmp, ' ');
                  continue;
            case '(':
            case '{':
            case '[':
                  b = 0;
                  if (!po)
                  {
                        switch (po = c)
                        {
                        case '(':
                              pc = ')';
                              break;
                        case '{':
                              pc = '}';
                              break;
                        case '[':
                              pc = ']';
                              break;
                        }
                        n++;
                  }
                  else if (c == po)
                        n++;
                  sfputc(ex->tmp, c);
                  continue;
            case ')':
            case '}':
            case ']':
                  b = 0;
                  if (!po)
                  {
                        exunlex(ex, c);
                        break;
                  }
                  sfputc(ex->tmp, c);
                  if (c == pc && --n <= 0)
                  {
                        if (t == po)
                              break;
                        po = 0;
                  }
                  continue;
            case ';':
                  b = 0;
                  if (!n)
                        break;
                  sfputc(ex->tmp, c);
                  continue;
            case '\'':
            case '"':
                  b = 0;
                  sfputc(ex->tmp, c);
                  ex->input->nesting++;
                  q = c;
                  while ((c = lex(ex)) != q)
                  {
                        if (c == '\\')
                        {
                              sfputc(ex->tmp, c);
                              c = lex(ex);
                        }
                        if (!c)
                        {
                              exerror("unterminated %c string", q);
                              goto eof;
                        }
                        if (c == '\n')
                        {
                              if (error_info.line)
                                    error_info.line++;
                              else error_info.line = 2;
                        }
                        sfputc(ex->tmp, c);
                  }
                  ex->input->nesting--;
                  continue;
            default:
                  b = 0;
                  sfputc(ex->tmp, c);
                  continue;
            }
            break;
      }
      (*ex->disc->reff)(ex, NiL, exlval.id, NiL, exstash(ex->tmp, NiL), 0, ex->disc);

                              /*..INDENT*/
                        }
                        goto again;
                  }
                  return exlval.id->lex;
            }
            return exlval.op = c;
      }
 eof:
      ex->eof = 1;
      return exlval.op = ';';
}

Generated by  Doxygen 1.6.0   Back to index