home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / compiler / as32 / lexer.c < prev    next >
C/C++ Source or Header  |  1991-03-22  |  7KB  |  320 lines

  1. /* ----------------------------------------------------------------------
  2.  * FILE: lexer.c
  3.  * PACKAGE: as31 - 8031/8051 Assembler.
  4.  *
  5.  * DESCRIPTION:
  6.  *    This file contains the lexical tokenizer for the assembler.
  7.  *    Since yacc is being used the lexer is called yylex().
  8.  *
  9.  *    In order to produce a listing, some record of the users
  10.  *    source line must be kept. This is done by adding
  11.  *    get_ch(), and unget_ch() routine which returns/ungets a character
  12.  *    but also places information into a secret array.
  13.  *
  14.  *    When a newline is encountered the text line is returned as
  15.  *    an attribute on the '\n' character.
  16.  *
  17.  * REVISION HISTORY:
  18.  *    Jan. 19, 1990 - Created. (Ken Stauffer)
  19.  *
  20.  * AUTHOR:
  21.  *    All code in this file written by Ken Stauffer (University of Calgary).
  22.  *    January, 1990.
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include "as31.h"
  29.  
  30. extern union ystack yylval;
  31. extern int pass;
  32.  
  33. struct symbol *looksym();
  34. struct opcode *lookop();
  35. char *malloc();
  36. int lineno;
  37.  
  38. static char line[100],*lineptr=line;
  39.  
  40. /* ----------------------------------------------------------------------
  41.  * get_ch:
  42.  *    Get a character from stdin, place char in line[]
  43.  */
  44.  
  45. get_ch()
  46. {
  47.     register int c;
  48.  
  49.     c = getchar();
  50.     if( c != EOF && lineptr - line < sizeof(line) )
  51.         *lineptr++ = c;
  52.     return(c);
  53. }
  54.  
  55. /* ----------------------------------------------------------------------
  56.  * unget_ch:
  57.  *    Unget a character and move lineptr back by one.
  58.  */
  59.  
  60. unget_ch(c)
  61. int c;
  62. {
  63.     ungetc(c,stdin);
  64.     if( lineptr > line )
  65.         lineptr--;
  66. }
  67.  
  68. /* ----------------------------------------------------------------------
  69.  * yylex:
  70.  *    The tokens themselves are returned via return(token)
  71.  *
  72.  *    Some tokens have attributes. These attributes are returned
  73.  *    by setting a global variable yylval:
  74.  *
  75.  *        yylval.value
  76.  *            numbers (any base)
  77.  *            strings (in pass 1).
  78.  *            bit positions .0, .1, .2, ...
  79.  *
  80.  *        yylval.str
  81.  *            strings (in pass 2).
  82.  *            '\n' (both passes).
  83.  *
  84.  *        yylval.sym
  85.  *            User defined symbols.
  86.  *
  87.  *        yylval.op
  88.  *            Reserved keyword (opcode/directive/misc.)
  89.  *
  90.  *        No other fields in yylval are used by yylex().
  91.  * 
  92.  *        Characters that do not have an attribute do
  93.  *        not set anything in the yylval variable.
  94.  *
  95.  */
  96.  
  97. yylex()
  98. {
  99.     static nl_flag=0;    /* sync. error messages and the cur. line */
  100.     register int c;
  101.     char buf[120];        /* temporary buffer */
  102.     char *p;        /* general pointer */
  103.     struct symbol *sym;
  104.     struct opcode *op;
  105.  
  106.     int octal=0,hex=0,decimal=0,binary=0;
  107.     register long value = 0;
  108.  
  109.     if( nl_flag ) {
  110.         nl_flag = 0;
  111.         lineno++;
  112.     }
  113.  
  114. for(;;) {
  115.     c = get_ch();
  116.     switch(c) {
  117.     case EOF: return(EOF);
  118.     case ' ':
  119.     case '\t':
  120.         break;
  121.  
  122.     case '\n':
  123.         nl_flag = 1;
  124.         yylval.str = line;
  125.         *lineptr = '\0';
  126.         lineptr = line;
  127.         return('\n');
  128.  
  129.     case ';':
  130.         while((c=get_ch()) != EOF && c!='\n');
  131.         nl_flag= 1;
  132.         yylval.str = line;
  133.         *lineptr = '\0';
  134.         lineptr = line;
  135.         return(c);
  136.  
  137.     case '"':
  138.         p = buf;
  139.         while((c=get_ch()) != EOF && c!='"' && c!='\n') {
  140.             if( c == '\\' ) {
  141.                 switch(c=get_ch()) {
  142.                 case 'n': c = '\n'; break;
  143.                 case 'r': c = '\r'; break;
  144.                 case 't': c = '\t'; break;
  145.                 case 'b': c = '\b'; break;
  146.                 case '"': c = '"'; break;
  147.                 case '\\': c = '\\'; break;
  148.                 default:
  149.                   error("Invalid escape character: \\%c",c);
  150.                   break;
  151.                 }
  152.             }
  153.             if( p-buf<sizeof(buf)-1 ) 
  154.                 *p++ = c;
  155.             else {
  156.                error("String constant longer than %d bytes",
  157.                     sizeof(buf));
  158.             }
  159.         }
  160.         *p = '\0';
  161.         if( c == '\n' || c == EOF ) {
  162.             error("String terminated improperly.");
  163.             unget_ch(c);
  164.         }
  165.  
  166.         if(pass1)
  167.             yylval.value = strlen(buf);
  168.         else {
  169.             if( (p = malloc(strlen(buf)+1)) == NULL )
  170.                error("Cannot allocate %d bytes",strlen(buf)+1);
  171.             strcpy(p,buf);
  172.             yylval.str = p;
  173.         }
  174.         return(STRING);
  175.  
  176.     case '.':
  177.         if( (c=get_ch())>='0' && c<='7' ) {
  178.             yylval.value = c-'0';
  179.             return(BITPOS);
  180.         }
  181.         unget_ch(c);
  182.         return('.');
  183.  
  184.     case '\'':
  185.         c = get_ch();
  186.         if( c=='\\' ) {
  187.             switch(c=get_ch()) {
  188.             case 'n': c = '\n'; break;
  189.             case 'r': c = '\r'; break;
  190.             case 't': c = '\t'; break;
  191.             case 'b': c = '\b'; break;
  192.             case '\\': c = '\\'; break;
  193.             case '\'': c = '\''; break;
  194.             default:
  195.                 error("Invalid escape character: \\%c",c);
  196.             }
  197.         }
  198.         if( get_ch() != '\'' )
  199.             error("Missing quote in character constant");
  200.         yylval.value = c;
  201.         return(VALUE);
  202.  
  203.     case '0':    /* parse a number            */
  204.     case '1':    /* could be followed by a:        */
  205.     case '2':    /*    'b','B' - Binary        */
  206.     case '3':    /*    'h','H' - Hex            */
  207.     case '4':    /*    'd','D' - Decimal        */
  208.     case '5':    /*    'o','O' - Octal            */
  209.     case '6':    /* *** Numbers must start with a digit    */
  210.     case '7':    /* Numbers could be also preceeded by:  */
  211.     case '8':    /*    0x    - Hex,    0b     - binary */
  212.     case '9':    /*    0    - Octal            */
  213.  
  214.         p = buf;
  215.         do {
  216.             if( p-buf<sizeof(buf)-1 )
  217.                 *p++ = c;
  218.             c = get_ch();
  219.         } while( c=='H' || c=='h' || c=='O' || c=='o' ||
  220.                 c=='x' || c=='X' || isxdigit(c) );
  221.         unget_ch(c);
  222.         *p = '\0';
  223.  
  224.  
  225.         /* Check any preceeding chars */
  226.         if( buf[0]=='0' && (buf[1]=='x' || buf[1]=='X') ) {
  227.                 hex++;
  228.                 buf[1] = '0';
  229.         } else if( buf[0]=='0' &&
  230.             (buf[1]=='b' || buf[1]=='B') ) {
  231.                 binary++;
  232.                 buf[1] = '0';
  233.             }
  234.         else if( buf[0]=='0' ) octal++;
  235.  
  236.         /* check any trailing chars */
  237.         c = *(p-1);
  238.         if( !hex && (c=='b' || c=='B') )
  239.             { binary++; *(p-1) = '\0'; }
  240.         else if( c=='H' || c=='h' )
  241.             { hex++; *(p-1) = '\0'; }
  242.         else if( !hex && (c=='D' || c=='d') )
  243.             { decimal++; *(p-1) = '\0'; }
  244.         else if( c=='O' || c=='o' )
  245.             { octal++; *(p-1) = '\0'; }
  246.         else if( !hex && !octal && !binary) decimal++;
  247.  
  248.         if( binary ) {
  249.             for(p=buf; *p; p++ ) {
  250.                 if( *p=='1' ) value = value<<1 + 1;
  251.                 else if( *p=='0' ) value = value<<1;
  252.                 else
  253.                   error("Invalid binary digit: %c",*p);
  254.             }
  255.             yylval.value = value;
  256.             return(VALUE);
  257.         }
  258.  
  259.         if( hex ) {
  260.             for(p=buf; *p; p++ ) {
  261.                 value <<= 4;
  262.                 if( isdigit(*p) )
  263.                     value += *p-'0';
  264.                 else if( *p>='a' && *p<='f' )
  265.                     value += *p-'a'+ 10;
  266.                 else if( *p>='A' && *p<='F' )
  267.                     value += *p-'A'+ 10;
  268.                 else
  269.                   error("Invalid hex digit: %c",*p);
  270.             }
  271.             yylval.value = value;
  272.             return(VALUE);
  273.         }
  274.  
  275.         if( decimal ) {
  276.             for(p=buf; *p; p++ ) {
  277.                 if( isdigit(*p) )
  278.                     value = value*10 + *p-'0';
  279.                 else
  280.                    error("Invalid decimal digit: %c",*p);
  281.             }
  282.             yylval.value = value;
  283.             return(VALUE);
  284.         }
  285.  
  286.         if( octal ) {
  287.             for(p=buf; *p; p++ ) {
  288.                 if( *p>='0' && *p<='7' )
  289.                     value = value<<3 + *p-'0';
  290.                 else
  291.                    error("Invalid octal digit: %c",*p);
  292.             }
  293.             yylval.value = value;
  294.             return(VALUE);
  295.         }
  296.  
  297.     default:
  298.         if( isalpha(c) || c=='_' ) {
  299.             p = buf;
  300.             do {
  301.                 if( p-buf<sizeof(buf)-1 )
  302.                     *p++ = c;
  303.                 c = get_ch();
  304.             } while( isalnum(c) || c=='_' );
  305.             *p = '\0';
  306.             unget_ch(c);
  307.             if( op = lookop(buf) ) {
  308.                 yylval.op = op;
  309.                 return(op->type);
  310.             }
  311.             sym = looksym(buf);
  312.             yylval.sym = sym;
  313.             return(SYMBOL);
  314.         } else
  315.             return(c);
  316.     } /* switch */
  317. } /* for */
  318.  
  319. } /* yylex */
  320.