%{ /* -*- C -*- */
/*
 * Assembler for DOCSIS cable modem configuration files
 *
 * $Id: lexan.l,v 1.2 2000/07/27 16:19:55 petras Exp $
 * 
 * Copyright (C) 2000  Dietmar Petras  <Dietmar.Petras@ELSA.de>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * History:
 * $Log: lexan.l,v $
 * Revision 1.2  2000/07/27 16:19:55  petras
 * Assignments between signed to unsigned corrected.
 *
 * Revision 1.1  2000/03/01 23:19:37  petras
 * Initial revision.
 *
 */

#include "o/yaccan_t.h"
#define YY_DECL int yylex(YYSTYPE *yylval)

#include "yaccan.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_STR_CONST 1024      /* Maximal length of a matched string. */

char StringBuf[MAX_STR_CONST];         /* Buffer for tokens belonging */
int  StringBufIndex = 0;               /* to a quoted string. */

int YYLineNo = 1;                     /* Lines counter */
const char *YYSourceName = "";        /* Name of current scanned file. */

int NoOverflow(int len);

%}

%x STR

digit           [0-9]
hexdigit        [0-9a-fA-f]

%%

[ \t\r]+ ; /* Eat white space */
\%.*    ; /* Eat comments up to end of line */
\n      { YYLineNo++; } /* count lines */

{digit}+ {
           /* ... extract integer number out of yytext ... */
           int token;
           unsigned long val = (unsigned long)atol(yytext);
           
           if (val<=0xff) {
              yylval->byte_val = (unsigned char)val;
              token = BYTE;
           } else {
              yylval->ulong_val = val;
              token = NUMBER;
           }
           return token;
        }

0x{hexdigit}{1,2} {
           /* ... extract integer number out of yytext ... */
	   int char_cnt = 2;
	   yylval->byte_val = 0;
	   
	   while (1) {
	     char c = yytext[char_cnt];
	     if (c=='\0' || c==':') break;
	     if (isdigit(c)) c -= '0';
	     else if (isalpha(c))  c = toupper(c) - 'A' + 10;
	     yylval->byte_val = yylval->byte_val*16 + c;
	     char_cnt++;
	   }
           return BYTE;
        }

=       { return IS; }
\{      { return OPEN_BRACKET; }
\}      { return CLOSE_BRACKET; }
\;      { return SEMICOLON; }

down_freq                       { return DOWN_FREQ; }
up_chan_id                      { return UP_CHAN_ID; }
network_access                  { return NETWORK_ACCESS; }
cos                             { return COS; }
modem_cap                       { return MODEM_CAP; }
vendor_id                       { return VENDOR_ID; }
upgrade_filename                { return UPGRADE_FILENAME; }
snmp_write_access               { return SNMP_WRITE_ACCESS; }
snmp_mib_object                 { return SNMP_MIB_OBJECT; }
cpe_mac_addr                    { return CPE_MAC_ADDR; }
bpi                             { return BPI; }
max_num_cpe                     { return MAX_NUM_CPE; }
upgrade_server                  { return UPGRADE_SERVER; }
vendor_specific_info            { return VENDOR_SPECIFIC_INFO; }
class_id                        { return CLASS_ID; }
max_down_rate                   { return MAX_DOWN_RATE; }
max_up_rate                     { return MAX_UP_RATE; }
up_chan_prio                    { return UP_CHAN_PRIO; }
min_up_rate                     { return MIN_UP_RATE; }
max_burst_size                  { return MAX_BURST_SIZE; }
cos_bpi_enable                  { return COS_BPI_ENABLE; }
concatenation                   { return CONCATENATION; }
authorize_wait_timeout          { return AUTHORIZE_WAIT_TIMEOUT; }
reauthorize_wait_timeout        { return REAUTHORIZE_WAIT_TIMEOUT; }
authorization_grace_time        { return AUTHORIZATION_GRACE_TIME; }
operational_wait_timeout        { return OPERATIONAL_WAIT_TIMEOUT; }
rekey_wait_timeout              { return REKEY_WAIT_TIMEOUT; }
tek_grace_time                  { return TEK_GRACE_TIME; }
authorize_reject_wait_timeout   { return AUTHORIZE_REJECT_WAIT_TIMEOUT; }

int                             { return INTEGER; }
string                          { return OCTET_STRING; }
null                            { return NULL_OBJ; }
object_id                       { return OBJECT_ID; }
ipaddress                       { return IPADDRESS; }

on                   { return ON; }
off                  { return OFF; }
enabled              { return ENABLE; }
disabled             { return DISABLE; }
allow                { return ALLOW; }
disallow             { return DISALLOW; }


({digit}{1,3}\.){3}{digit}{1,3} { yylval->string_val=strdup(yytext); return IP_ADDR_STRING; }
({hexdigit}{1,}\.)+{hexdigit}{1,} { yylval->string_val=strdup(yytext); return SNMP_OBJ_ID; }
({hexdigit}{1,2}:){5}{hexdigit}{1,2} { yylval->string_val=strdup(yytext); return MAC_ADDR_STRING; }


\"      {
           /* Saw a start of string, start STR analyser */
           StringBufIndex = 0;
           BEGIN(STR);
        }

<STR>\n {
           /* error - unterminated string constant. */
           /* Ignore string and print error message. */
           yyerror("Syntax error: Unterminated string");
           YYLineNo++;
           /* return to initial analyser */
           BEGIN(INITIAL);
        }

<STR>\" {
           /* Closing quote */
           StringBuf[StringBufIndex++] = '\0';
           yylval->string_val=(char*)malloc(StringBufIndex);
           strcpy(yylval->string_val, StringBuf);
           BEGIN(INITIAL);
           return (STRING);
        }

<STR>\\[0-7]{1,3} {
           /* Octal escape sequence. */
           if (NoOverflow(StringBufIndex)) {
              int result;
              sscanf(yytext+1, "%o", &result);
              if (result > 0xff) {
                 /* Error, constant is out of bounds. */
                 yyerror(NULL);
                 fprintf(stderr, "Error: illegal escape sequence `%s'\n", yytext);
              }
              StringBuf[StringBufIndex++] = result & 0xff;
           }
        }

<STR>\\[0-9]+ {
           /* Print error messege on bad escape sequence */
           /* like '\48' or '\077777' */
           yyerror(NULL);
           fprintf(stderr, "Error: illegal escape sequence `%s'\n", yytext);
        }

<STR>\\n {
           /* Newline-escape sequence */
           if (NoOverflow(StringBufIndex)) StringBuf[StringBufIndex++] = '\n';
        }

<STR>\\r {
           /* Return-escape sequence */
           if (NoOverflow(StringBufIndex)) StringBuf[StringBufIndex++] = '\r';
        }

<STR>\\t {
           /* Tab-escape sequence */
           if (NoOverflow(StringBufIndex)) StringBuf[StringBufIndex++] = '\t';
        }

<STR>\\. {
           /* a normal quoted character */
           if (NoOverflow(StringBufIndex)) StringBuf[StringBufIndex++] = yytext[1];
        }

<STR>. {
           /* Any other character */
           if (NoOverflow(StringBufIndex)) StringBuf[StringBufIndex++] = yytext[0];
        }

[^ \t\n;{}\"]+  {
           yyerror(NULL);
           fprintf(stderr, "Syntax error at `%s'\n", yytext);
        }
%%
int yywrap(void) {
   return(1);
}

int NoOverflow(int len) {
   int result = 1;
   if (len+2 > MAX_STR_CONST) {
      yyerror("string overflow");
      result = 0;
   }
   return result;
}


/* {{{ Local variables */

/*
  Local variables:
  folded-file: t
  c-basic-offset: 2
  End:
*/

/* }}} */
