INTERNET-DRAFT            Expires January 1997            INTERNET-DRAFT

Draft                 SNMPv2 Lexical Specification         July 30, 1996


                        A Lexical Specification
                             for the SNMPv2
                          MIB Module Language

                  <draft-perkins-snmpv2-lex-spec-00.txt>

                             July 30, 1996

                            David T. Perkins
                         dperkins@scruznet.com



1. Status of this Memo

   This document is an Internet Draft.  Internet Drafts are working
   documents of the Internet Engineering Task Force (IETF), its Areas,
   and its Working Groups. Note that other groups may also distribute
   working documents as Internet Drafts.

   Internet Drafts are draft documents valid for a maximum of six
   months.  Internet Drafts may be updated, replaced, or obsoleted by
   other documents at any time.  It is not appropriate to use Internet
   Drafts as reference material or to cite them other than as a
   "working draft" or "work in progress."

   To learn the current status of any Internet-Draft, please check the
   "1id-abstracts.txt" listing contained in the internet-drafts Shadow
   Directories on:

         ftp.is.co.za (Africa)
         nic.nordu.net (Europe)
         ds.internic.net (US East Coast)
         ftp.isi.edu (US West Coast)
         munnari.oz.au (Pacific Rim)
















Expires 1/30/1997                                               [Page 1]


Draft                 SNMPv2 Lexical Specification         July 30, 1996



2. Introduction

This memo integrates the specifications for the lexical elements of the
MIB module language from section 8 of the ASN.1 specification[4],
augmented by the ASN.1 macros defined for the MIB module language, and
modified by textual descriptions in SMIv2(RFCs 1902[1], 1903[2] and
1904[3]); and the standard practices found in most of the leading MIB
compilers that are accepted by the SNMP community.  Also include in this
memo is a Lex specification for the tokens of the language.

This memo is a rough first draft as requested by the SNMPv2 WG at the
SMI Documentation BOF during the June 1996 IETF.




3. Lexical Elements

The source for a MIB module must be contained in a MIB module source
file.  One or more MIB modules may be contained in a source file.  A
source file consists of a sequence of lines, each terminated by an end-
of-line.  ASN.1 has no restrictions on the length of a line or the
number of lines in a MIB module source file.
[??What should the limits be here?]
Conforming MIB module compilers must allow lines to be at least 255
characters long (excluding the end-of-line indicator), and must allow
source files to contain at least 65535 lines.


3.1 Characters in a Source File

The "normal" characters in a source file are:
     A-Z the uppercase letters
     a-z the lowercase letters
     0-9 the decimal digits
     { left curly brace
     } right curly brace
     ( left parenthesis
     ) right parenthesis
     : colon
     ; semicolon
     , coma
     - hyphen (dash)
     . period
     | vertical bar
     = equal sign
     " quote
     ' apostrophe
     a space
     a tab


Expires 1/30/1997                                               [Page 2]


Draft                 SNMPv2 Lexical Specification         July 30, 1996



The "additional" characters are the remaining printable characters in
the 7-bit ASCII character set. The "normal" and "additional" characters
are only allowed in comments and in quoted strings.  Note that the ASN.1
language includes characters "<", ">", "[", and "]", which are not used
in the MIB module language.


3.2 Tokens

The characters in a MIB module source file form a stream of tokens. The
tokens are identifiers, keywords, literals (i.e., constants),
punctuation, and white space.  White space consists of space characters,
line terminators, tab characters, and comments.  White space is ignored
other than for use to separate otherwise adjacent identifiers, keywords,
and literals.  If the input has been parsed into tokens up to a given
character, the next token is the longest string of characters that could
possibly constitute a token.


3.3 Comments

A comment is started with a pair of adjacent hyphens (--) and is ended
with the next pair of adjacent hyphens or the end of the line, whichever
comes first.  A comment may include any of the printable characters in
the 7-bit ASCII character set, and spaces and tabs.  A comment may occur
between any two tokens and functions as white space.


3.4 Identifiers

An identifier consists of 1 to 64 letters, digits, and hyphens.  The
initial character must be a letter.  A hyphen cannot be the last
character of an identifier.  A hyphen cannot be immediately followed by
another hyphen in an identifier. (NOTE: ASN.1 has no limit on number of
characters in an identifier. Otherwise, the lexical rules for
identifiers are identical.)

There are two types of identifiers which are distinguished by the case
of the initial letter.  A "ucName" is an identifier that starts with an
uppercase letter.  A "lcName" is an identifier that starts with a
lowercase letter.  Identifiers whose lengths are greater than 24 may
cause compatibility difficulties with tools that process MIB modules

Also note that SMIv2 imposes restrictions on use of hyphens in most
identifiers.  Those restrictions are noted in the grammar description.







Expires 1/30/1997                                               [Page 3]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


3.5 Keywords

Some identifiers are reserved for use as keywords.  The keywords can not
be used as ucNames.  The keywords consist of the sub-set of ASN.1
keywords used in the MIB module language, and the elements of the macros
defined for SNMP that conform to the rules for ucNames.

     The following are keywords in ASN.1, but are not keywords in the
     MIB module language:
          ABSENT, ANY, APPLICATION, BIT, BOOLEAN, BY, CHOICE,
          COMPONENT, COMPONENTS, DEFAULT, DEFINED, ENUMERATED,
          EXPLICIT, EXPORTS, EXTERNAL, FALSE, IMPLICIT, MAX, MIN,
          MINUS-INFINITY, NULL, OPTIONAL, PLUS-INFINITY, PRESENT,
          PRIVATE, REAL, SET, TAGS, TRUE, UNIVERSAL, and WITH

     The following are ASN.1 keywords used in the MIB module language:
          BEGIN, DEFINITIONS, END, FROM, IDENTIFIER, IMPORTS,
          INCLUDES, INTEGER, OBJECT, OCTET, OF, SEQUENCE, SIZE,
          and STRING

     The following are keywords only in the MIB module language:
          ACCESS, AGENT-CAPABILITIES, AUGMENTS, BITS,
          CONTACT-INFO, CREATION-REQUIRES, Counter32, Counter64,
          DEFVAL, DESCRIPTION, DISPLAY-HINT, GROUP, Gauge32,
          IMPLIED, INDEX, Integer32, IpAddress, LAST-UPDATED,
          MANDATORY-GROUPS, MIN-ACCESS, MODULE, MODULE-
          COMPLIANCE, MODULE-IDENTITY, NOTIFICATION-GROUP,
          NOTIFICATION-TYPE, OBJECT-GROUP, OBJECT-IDENTITY,
          OBJECT-TYPE, OBJECTS, ORGANIZATION, Opaque,
          PRODUCT-RELEASE, REFERENCE, REVISION, STATUS, SUPPORTS,
          SYNTAX, TEXTUAL-CONVENTION, TimeTicks, UNITS,
          Unsigned32, VARIATION, and WRITE-SYNTAX


3.6 Punctuation

The following is a list of single characters used as punctuation tokens
in the MIB module language:
     { left curly brace
     } right curly brace
     ( left parenthesis
     ) right parenthesis
     : colon
     ; semicolon
     , coma
     - hyphen (dash)
     . period
     | vertical bar





Expires 1/30/1997                                               [Page 4]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


The following is a list of character combinations used as punctuation
tokens in the MIB module language:
     .. two periods
     ::= two colons and an equal sign


3.7 Literals

The literals (or constants) are unsigned integers (called numbers),
character strings, hexadecimal strings, and binary strings. (NOTE: the
character strings in the MIB module language are not ASN.1 "cstrings".)


3.7.1 Numbers

A number consists of one or more decimal digits. The first digit may not
be zero unless the number is a single digit.  The maximum value of a
number is 4294967295. (NOTE: there is no limit on the maximum value of
numbers in ASN.1.)


3.7.2 Binary Strings

A binary string consists of an arbitrary number (possibly zero) of zeros
and ones, preceded by a single (') and followed by either the pair ('B)
or ('b).  The maximum length is 128 binary digits. (NOTE: ASN.1
terminates a binary string with only a ('B).  Also, ASN.1 has no limit
on the length of a binary string.)


3.7.3 Hexadecimal Strings

A hexadecimal string consists of an arbitrary number (possibly zero) of
hexadecimal digits, preceded by a single (') and followed by either the
pair ('H) or ('h).  The maximum length is 128 hexadecimal digits.  The
hexadecimal digits are the characters "0", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "A", "a", "B", "b", "C", "c", "D", "d", "E", "e", "F",
and "f".  (NOTE: ASN.1 terminates a hexadecimal string with only a ('H).
Also, ASN.1 recognizes only the uppercase letters as hexadecimal digits
and has no limit on the length of a hexadecimal string.)


3.7.4 Strings

A character string consists of an arbitrary number (possibly zero) of
the 7-bit graphic ASCII characters except the quote character ("), tabs,
spaces, and line terminators, preceded and followed by the quote
character ("). A line terminator is encoded in a quoted string as a
newline (i.e., the '\n' character).  The maximum length of a character
string is 8192 characters.



Expires 1/30/1997                                               [Page 5]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


4. Lex Specification

The specification below is the input for the Lex program, a widely used
program to generate lexical analyzers.  The specification can also be
processed by the Flex program from the GNU project, which is a clone of
Lex.



4.1 File v-scan.l

/* file: v-scan.l - scanner for SNMPv1 and SNMPv2
 *
 * Copyright 1996 David T. Perkins. All Rights Reserved.
 *
 * David T. Perkins grants a non-exclusive license to use, copy,
 * modify, and distribute this software for any purpose and
 * without fee, provided that this copyright notice and license
 * appear on all copies and supporting documentation.
 * David T. Perkins makes no representations about the suitability
 * of this software for any particular purpose. The software is
 * supplied "AS IS", and David T. Perkins makes no warranty, either
 * express or implied, as to the use, operation, condition, or
 * performance of the software.
 * David T. Perkins retains all title and ownership in the software.
 *
 *
 * $Revision: 1.0.1 $
 * $Date: 28-jul-96 $
 *
*/

%{
/* file: v-scan.c - generated scanner for SNMPv1 and SNMPv2
 *                  from v-scan.l
 *
*/

#include <stdlib.h>
#include <errno.h>
#include <limits.h>


#include "v-types.h"
#include "v-scan.h"
#include "yystype.h"

MIBLOC locCur = { NULL, 1, 1 }; /* current location (line, column) */

BOOL fInStr;                    /* flag that in string */
USHORT usType;                  /* token type */


Expires 1/30/1997                                               [Page 6]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


USHORT usColStart;              /* start column for a string */
BOOL fOk2DropLWS;               /* flag to allow dropping LWS */
BOOL fDropLWS;                  /* flag that dropping leading
                                    white space */

#define MAXSZNUM 10             /* max digits in a number */
#define MAXNUMSZ "4294967295"   /* max value for a number */
#define MAXNUMUL  4294967295LU

#define MAXSZNA 64              /* max length of a name */
CHAR szNa[MAXSZNA+1];           /* buffer for a name */
USHORT cSzNa;                   /* number of bytes in buffer */

#define MAXSZSTR 8192           /* max length of a string */
/* note that MAXSZBSTR and MAXSZHBSTR
*  must be less than or equal to MAXSZSTR */
#define MAXSZBSTR 128           /* max length of a binary string */
#define MAXSZHSTR 128           /* max length of a hex string */
CHAR szStr[MAXSZSTR+1];         /* buffer for a string */
USHORT cSzStr;                  /* number of bytes in buffer */

%}
 /* states for scanning: */
   /* in a hex or bin string */
%s InHexOrBinString
   /* in a quoted string */
%s InQuotedString
   /* in a comment */
%s InComment
   /* in a name */
%s InName
   /* in a number */
%s InNumber
   /* leading zeros of a number */
%s LeadingZeros


%n 800      /* increased number of DFA entries */
%e 1500     /* increased number of NFA entries */

%%

  /* Comment */
<INITIAL>"--" {
        /* start of a comment */
        locCur.usColNo = (USHORT)(locCur.usColNo + yyleng);
        BEGIN InComment;
        }

<InComment>"--" {
        /* finished with comment */


Expires 1/30/1997                                               [Page 7]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        locCur.usColNo = (USHORT)(locCur.usColNo + yyleng);
        BEGIN 0;
        }

<InComment>"\n" {
        /* finished with comment */
        locCur.ulLineNo++;
        locCur.usColNo = 1;
        BEGIN 0;
        }

<InComment>. {
        /* any other character in the comment */
        locCur.usColNo++;
        }

  /* special tokens */
<INITIAL>"{" {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchLCB);
        }

<INITIAL>"}" {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchRCB);
        }

<INITIAL>"(" {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchLPR);
        }

<INITIAL>")" {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchRPR);
        }

<INITIAL>";" {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchSEMI);
        }

<INITIAL>"," {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchCOMMA);


Expires 1/30/1997                                               [Page 8]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        }

<INITIAL>"-" {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchMINUS);
        }

<INITIAL>"." {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchDOT);
        }

<INITIAL>"|" {
        yylval.usval.loc = locCur;
        locCur.usColNo++;
        return(yylval.usval.us = XchOR);
        }

<INITIAL>".." {
        yylval.usval.loc = locCur;
        locCur.usColNo = (USHORT)(locCur.usColNo + yyleng);
        return(yylval.usval.us = XtokDOTDOT);
        }

<INITIAL>"::=" {
        yylval.usval.loc = locCur;
        locCur.usColNo = (USHORT)(locCur.usColNo + yyleng);
        return(yylval.usval.us = XtokIS);
        }


  /* white space */
<INITIAL>[ \t] {
        /* space or tab */
        locCur.usColNo++;
        }

<INITIAL>"\n" {
        /* a newline */
        locCur.ulLineNo++;
        locCur.usColNo = 1;
        }


  /* Name starting with uppercase letter,
     including keywords for the parser */
<INITIAL>[A-Z] {
        /* ucName (identifier that starts with
           an uppercase letter) */


Expires 1/30/1997                                               [Page 9]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        yylval.strval.pStr = NULL;
        yylval.strval.loc = locCur;
        locCur.usColNo++;
        cSzNa = 1;
        szNa[0] = yytext[0];
        usType = XtokUCNAME;
        BEGIN InName;
        }

  /* Name starting with lowercase letter */
<INITIAL>[a-z] {
        /* lcName (identifier that starts with
           a lowercase letter) */
        yylval.strval.pStr = NULL;
        yylval.strval.loc = locCur;
        locCur.usColNo++;
        cSzNa = 1;
        szNa[0] = yytext[0];
        usType = XtokLCNAME;
        BEGIN InName;
        }

  /* common for ucName and lcName */
<InName>"--" {
        /* a comment terminates a name */
        locCur.usColNo = (USHORT)(locCur.usColNo + yyleng);
        BEGIN InComment;

        /* terminate saved string and check on size of name */
        if (cSzNa > MAXSZNA) {
            yyerror("Name too big, max size is %d", MAXSZNA);
            szNa[MAXSZNA] = 0;
        } else {
            szNa[cSzNa] = 0;
        }

        /* check if keyword */
        if ((cSzNa <= MAXSZNA) &&
                (usType == XtokUCNAME) &&
                ((yylval.usval.us = getKwType(&szNa[0])) != 0)) {
            /* was a keyword */
            return(yylval.usval.us);
        }

        /* Otherwise, store name in string table */
        yylval.strval.pStr = StrTabInsert(&szNa[0]);
        return(usType);
        }

<InName>"-"/([A-Z]|[a-z]|[0-9]) {
        /* a hyphen in name */


Expires 1/30/1997                                              [Page 10]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        locCur.usColNo++;
        if (cSzNa < MAXSZNA) {
            szNa[cSzNa++] = yytext[0];
        } else if (cSzNa == MAXSZNA) {
            /* max chars in string */
            cSzNa++;
        } /* else, too many chars, so do nothing */
        }

<InName>([A-Z]|[a-z]|[0-9]) {
        /* a letter or digit in name */
        locCur.usColNo++;
        if (cSzNa < MAXSZNA) {
            szNa[cSzNa++] = yytext[0];
        } else if (cSzNa == MAXSZNA) {
            /* max chars in string */
            cSzNa++;
        } /* else, too many chars, so do nothing */
        }

<InName>(.|\n) {
        /* anything else or newline terminates the name */

        /* pushback input */
        yyless(0);
        BEGIN 0;

        /* terminate saved string and check on size of name */
        if (cSzNa > MAXSZNA) {
            yyerror("Name too big, max size is %d", MAXSZNA);
            szNa[MAXSZNA] = 0;
        } else {
            szNa[cSzNa] = 0;
        }

        /* check if keyword */
        if ((cSzNa <= MAXSZNA) &&
                (usType == XtokUCNAME) &&
                ((yylval.usval.us = getKwType(&szNa[0])) != 0)) {
            /* was a keyword */
            return(yylval.usval.us);
        }

        /* Otherwise, store name in string table */
        yylval.strval.pStr = StrTabInsert(&szNa[0]);
        return(usType);
        }


  /* number */
<INITIAL>0/[1-9] {


Expires 1/30/1997                                              [Page 11]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        /* a zero followed by nonzero digit */
        locCur.usColNo++;
        yyerror("A leading zero on a number is illegal");
        }

<INITIAL>0/0 {
        /* a zero followed by a zero */
        locCur.usColNo++;
        yyerror("Leading zero(s) on a number are illegal");
        BEGIN LeadingZeros;
        }

<LeadingZeros>0/0 {
        /* multiple leading zeros */
        locCur.usColNo++;
        }

<LeadingZeros>0 {
        /* zero followed by anything else */
        /* pushback input, and rescan as a number */
        yyless(0);
        BEGIN 0;
        }

<INITIAL>[0-9] {
        /* start of a number */
        yylval.ulval.loc = locCur;
        locCur.usColNo++;
        cSzNa = 1;
        szNa[0] = yytext[0];
        BEGIN InNumber;
        }

<InNumber>[0-9] {
        /* digits in the number */
        locCur.usColNo++;
        if (cSzNa < MAXSZNUM) {
            /* add char to string */
            szNa[cSzNa++] = yytext[0];
        } else if (cSzNa == MAXSZNUM) {
            /* max chars in string */
            cSzNa++;
        } /* else, too many chars, so do nothing */
        }


<InNumber>(.|\n) {
        /* anything else in input terminates the number */

        /* terminate string */
        szNa[(cSzNa < MAXSZNUM) ? cSzNa : MAXSZNUM] = 0;


Expires 1/30/1997                                              [Page 12]


Draft                 SNMPv2 Lexical Specification         July 30, 1996



        /* check if number is valid, and compute value */
        if ((cSzNa > MAXSZNUM)  ||
                ((cSzNa == MAXSZNUM) &&
                        ((strcmp(szNa, MAXNUMSZ) > 0)))) {
            yylval.ulval.ul = MAXNUMUL;
            yyerror("Number too big, max value is %lu",
                        MAXNUMUL);
        } else {
            /* compute value of number */
            {
                CHAR *pch;

                yylval.ulval.ul = 0;
                for (pch = &szNa[0]; *pch != 0; pch++) {
                    yylval.ulval.ul = yylval.ulval.ul*10 +
                                        (*pch - '0');
                }
            }
        }

        /* check for character */
        if ((('a' <= yytext[0]) && (yytext[0] <= 'z')) ||
                (('A' <= yytext[0]) && (yytext[0] <= 'Z')))
            yyerror(
                "Missing separator between number and character");

        /* pushback input */
        yyless(0);
        BEGIN 0;
        return(XtokNUMBER);
        }


  /* Hex or Binary string */
<INITIAL>"'" {
        /* start of a HEX or BINARY string */
        yylval.strval.pStr = NULL;
        yylval.strval.loc = locCur;
        locCur.usColNo++;
        cSzStr = 0;
        fInStr = TRUE;
        BEGIN InHexOrBinString;
        }

<InHexOrBinString>[0-9a-fA-F] {
        /* in a HEX or BINARY string */
        locCur.usColNo++;
        if (cSzStr < MAXSZSTR) {
            /* add char to string */
            szStr[cSzStr++] = yytext[0];


Expires 1/30/1997                                              [Page 13]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        } else if (cSzStr == MAXSZSTR) {
            /* max chars in string */
            cSzStr++;
        } /* else, too many chars, so do nothing */
        }

<InHexOrBinString>"'"[Hh] {
        /* end of HEX string */
        locCur.usColNo = (USHORT)(locCur.usColNo + yyleng);

        /* terminate string and check on size */
        if (cSzStr > MAXSZHSTR) {
            yyerror(
                "Hexadecimal string too long, max length is %d",
                MAXSZHSTR);
            szStr[MAXSZHSTR] = 0;
        } else {
            szStr[cSzStr] = 0;
        }

        BEGIN 0;
        fInStr = FALSE;

        /* store in string table */
        yylval.strval.pStr = StrTabInsert(&szStr[0]);
        return(XtokHSTR);
        }

<InHexOrBinString>"'"[Bb] {
        /* end of BINARY string */
        locCur.usColNo = (USHORT)(locCur.usColNo + yyleng);

        /* terminate string and check on size */
        if (cSzStr > MAXSZBSTR) {
            yyerror("Binary string too long, max length is %d",
                        MAXSZBSTR);
            szStr[MAXSZBSTR] = 0;
        } else {
            szStr[cSzStr] = 0;
        }

        /* check if all binary digits */
        {   CHAR *pch;

            for (pch = &szStr[0]; *pch != 0; pch++) {
                if ((*pch != '0') && (*pch != '1')) {
                    yyerror("Invalid digit in Binary string");
                    *pch = 0;
                    break;
                }
            }


Expires 1/30/1997                                              [Page 14]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        }

        BEGIN 0;
        fInStr = FALSE;

        /* store in string table */
        yylval.strval.pStr = StrTabInsert(&szStr[0]);
        return(XtokBSTR);
        }

<InHexOrBinString>(.|\n) {
        /* invalid char in HEX or BINARY string */
        /* pushback input */
        yyless(0);
        fInStr = FALSE;
        BEGIN 0;
        yyerror("Invalid Hexadecial or Binary string");
        }

  /* quoted string */
<INITIAL>\" {
        /* start of a quoted string */
        yylval.strval.pStr = NULL;
        yylval.strval.loc = locCur;
        usColStart = locCur.usColNo++;
        if (fOk2DropLWS)
            fDropLWS = FALSE;
        cSzStr = 0;
        fInStr = TRUE;
        BEGIN InQuotedString;
        }

<InQuotedString>"\n" {
        /* a newline in the quoted string */
        locCur.ulLineNo++;
        locCur.usColNo = 1;
        if (fOk2DropLWS)
            fDropLWS = TRUE;

        /* add char to string if room */
        if (cSzStr < MAXSZSTR) {
            /* add char to string */
            szStr[cSzStr++] = yytext[0];
        } else if (cSzStr == MAXSZSTR) {
            /* max chars in string */
            cSzStr++;
        } /* else, too many chars, so do nothing */
        }

<InQuotedString>[^"\n] {
        /* a character in a quoted string */


Expires 1/30/1997                                              [Page 15]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        locCur.usColNo++;

        /* check for leading white space */
        if (fDropLWS) {
            /* check if before start column for string */
            /* and char is white space */
            if ((locCur.usColNo > usColStart) ||
                    ((yytext[0] ^= ' ') && (yytext[0] != '\t')))
               /* stop ignoring leading whitespace */
               fDropLWS = FALSE;
        }

        /* add char if not dropping leading white space */
        if (!fDropLWS) {
            /* add char to string if room */
            if (cSzStr < MAXSZSTR) {
                /* add char to string */
                szStr[cSzStr++] = yytext[0];
            } else if (cSzStr == MAXSZSTR) {
                /* max chars in string */
                cSzStr++;
            } /* else, too many chars, so do nothing */
        }
        }

<InQuotedString>\" {
        /* end of quoted string */
        locCur.usColNo++;

        /* terminate string and check on size */
        if (cSzStr > MAXSZSTR) {
            yyerror("String too long, max length is %d",
                        MAXSZSTR);
            szStr[MAXSZSTR] = 0;
        } else {
            szStr[cSzStr] = 0;
        }

        BEGIN 0;
        fInStr = FALSE;

        /* store in string table */
        yylval.strval.pStr = StrTabInsert(&szStr[0]);
        return(XtokSTRING);
        }

  /* anything else in the input */
<INITIAL>. {
        /* anything else in the input */
        locCur.usColNo++;
        yyerror("Unrecognized item");


Expires 1/30/1997                                              [Page 16]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        }


%%

/* parameters for hash function */
#define HASHSIZE 143
#define HASHBITS (sizeof(USHORT)*8)
#define HASH3_4  ((HASHBITS*3)/4)
#define HASH1_8  (HASHBITS/8)
#define HASH_HI  (~((USHORT)(~0) >> HASH1_8))

/* hash list */
KEYWORDNAME *apkwNa[HASHSIZE];


/** hashNa - hash a name
*
* From Compiler: Principles, Techniques, and Tools,
*       P.J. Weinberger
*
* call with:
*   pszName - name
*
* returns:
*   hash value
*/
    USHORT
#ifdef __STDC__
hashNa(PSZ pszName)
#else
hashNa(pszName)
    PSZ pszName;
#endif /* __STDC__ */
{
    register USHORT usVal;
    register USHORT usTmp;

    for (usVal = 0; *pszName != 0; pszName++) {
        usVal = (USHORT)((usVal << HASH1_8) + *pszName);
        if ((usTmp = (USHORT)(usVal & HASH_HI)) != 0) {
            usVal = (USHORT)((usVal ^ (usTmp >> HASH3_4))
                        & ~HASH_HI);
        }
    }

    return((USHORT)(usVal%HASHSIZE));

} /* hashNa */




Expires 1/30/1997                                              [Page 17]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


/** bldKwHash - build hash table for keywords
*
*/
    VOID
#ifdef __STDC__
bldKwHash(VOID)
#else
bldKwHash()
#endif /* __STDC__ */
{
    INT i;
    USHORT iHash;


    for (i = 0; i < HASHSIZE; i++) {
        apkwNa[i] = NULL;
    }

    for (i = cKw - 1; i >= 0; i--) {
        iHash = hashNa(kwNa[i].pszName);
        kwNa[i].pHashNext = apkwNa[iHash];
        apkwNa[iHash] = &(kwNa[i]);
    }

} /* bldKwHash */


#define MXFREQ 10

/** freqKwHash - print frequences of keyword hash collisions
*
*/
    VOID
#ifdef __STDC__
freqKwHash(VOID)
#else
freqKwHash()
#endif /* __STDC__ */
{
    INT i;
    USHORT iHash;
    USHORT acFreq[MXFREQ];
    KEYWORDNAME *pkwNa;


    for (i = 0; i < MXFREQ; i++) {
        acFreq[i] = 0;
    }

    for (iHash = 0; iHash < HASHSIZE; iHash++) {
        for (i = 0, pkwNa = apkwNa[iHash];


Expires 1/30/1997                                              [Page 18]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


                (pkwNa != NULL) && (i < (MXFREQ-1)); i++) {
            pkwNa = pkwNa->pHashNext;
        }
        acFreq[i]++;
        if (i > 1) {
            fprintf(fhMsg, "Hash: %d, %d hits\n", iHash, i);
            for (pkwNa = apkwNa[iHash]; pkwNa != NULL;
                        pkwNa = pkwNa->pHashNext) {
                fprintf(fhMsg, "  \"%s\"\n", pkwNa->pszName);
            }
        }

    }

    for (i = 0; i < MXFREQ; i++) {
        if (acFreq[i] != 0)
            fprintf(fhMsg, "%3d: %d\n", i, acFreq[i]);
    }

} /* freqKwHash */


/** getKwType - lookup item to see if keyword
*
* call with:
*   pszNa - name of item
*
* returns:
*   0 - if not a keyword
*   otherwise, type of keyword
*
*/
    USHORT
#ifdef __STDC__
getKwType(PSZ pszNa)
#else
getKwType(pszNa)
    PSZ pszNa;
#endif /* __STDC__ */
{
    USHORT ikwNa;
    KEYWORDNAME *pkwNa;


    /* hash name */
    ikwNa = hashNa(pszNa);


    /* check names on hash chain */
    for (pkwNa = apkwNa[ikwNa]; pkwNa != NULL;
                pkwNa = pkwNa->pHashNext) {


Expires 1/30/1997                                              [Page 19]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        if (strcmp(pszNa, pkwNa->pszName) == 0)
            /* name matched, so return type */
            return(pkwNa->usType);
    }

    /* no match */
    return(0);

} /* getKwType */


/** yywrap - check for more input since scanner (yylex)
*            got EOF from yygetc
*
* returns:
*   0 - more input available on yyin
*   1 - finished with all input
*/
    INT
#ifdef __STDC__
yywrap(VOID)
#else
yywrap()
#endif /* __STDC__ */
{
    if (fInStr) {
        yyerror("EOF in string");
    }
    return(1);

} /* yywrap */


/* end of file */


4.2 File v2c-scan.c

/* file: v2c-sc.c - scanner data and functions for SNMPv2C
 *
 * Copyright 1996 David T. Perkins. All Rights Reserved.
 *
 * David T. Perkins grants a non-exclusive license to use, copy,
 * modify, and distribute this software for any purpose and
 * without fee, provided that this copyright notice and license
 * appear on all copies and supporting documentation.
 * David T. Perkins makes no representations about the suitability
 * of this software for any particular purpose. The software is
 * supplied "AS IS", and David T. Perkins makes no warranty, either
 * express or implied, as to the use, operation, condition, or
 * performance of the software.


Expires 1/30/1997                                              [Page 20]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


 * David T. Perkins retains all title and ownership in the software.
 *
 *
 * $Revision: 1.0.2 $
 * $Date: 27-jul-96 $
 *
*/

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>


#include "v-types.h"
#include "v-scan.h"
#include "v2c-prs.h"


PSZ pszScanNa = "v2c-scan";
PSZ pszScanVer = "v1.0.2";
PSZ pszScanCopyright =
    "Copyright 1996 David T. Perkins. All Rights Reserved.";

/* items whose value is defined in parser output */
USHORT XchLCB = chLCB;
USHORT XchRCB = chRCB;
USHORT XchLPR = chLPR;
USHORT XchRPR = chRPR;
USHORT XchSEMI = chSEMI;
USHORT XchCOMMA = chCOMMA;
USHORT XchMINUS = chMINUS;
USHORT XchDOT = chDOT;
USHORT XchOR = chOR;
USHORT XtokDOTDOT = tokDOTDOT;
USHORT XtokIS = tokIS;
USHORT XtokUCNAME = tokUCNAME;
USHORT XtokLCNAME = tokLCNAME;
USHORT XtokNUMBER = tokNUMBER;
USHORT XtokBSTR = tokBSTR;
USHORT XtokHSTR = tokHSTR;
USHORT XtokSTRING = tokSTRING;

/* keywords */
KEYWORDNAME FAR kwNa[] = {
        { "ACCESS", kwACCESS, NULL },
        { "AGENT-CAPABILITIES", kwAGENT_CAPABILITIES, NULL },
        { "AUGMENTS", kwAUGMENTS, NULL },
        { "BEGIN", kwBEGIN, NULL },
        { "BITS", kwBITS, NULL },
        { "CONTACT-INFO", kwCONTACT_INFO, NULL },
        { "Counter32", kwCOUNTER32, NULL },


Expires 1/30/1997                                              [Page 21]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        { "Counter64", kwCOUNTER64, NULL },
        { "CREATION-REQUIRES", kwCREATION_REQUIRES, NULL },
        { "DEFINITIONS", kwDEFINITIONS, NULL },
        { "DEFVAL", kwDEFVAL, NULL },
        { "DESCRIPTION", kwDESCRIPTION, NULL },
        { "DISPLAY-HINT", kwDISPLAY_HINT, NULL },
        { "END", kwEND, NULL },
        { "FROM", kwFROM, NULL },
        { "Gauge32", kwGAUGE32, NULL },
        { "GROUP", kwGROUP, NULL },
        { "IDENTIFIER", kwIDENTIFIER, NULL },
        { "IMPLIED", kwIMPLIED, NULL },
        { "IMPORTS", kwIMPORTS, NULL },
        { "INCLUDES", kwINCLUDES, NULL },
        { "INDEX", kwINDEX, NULL },
        { "INTEGER", kwINTEGER, NULL },
        { "Integer32", kwINTEGER32, NULL },
        { "IpAddress", kwIPADDRESS, NULL },
        { "LAST-UPDATED", kwLAST_UPDATED, NULL },
        { "MANDATORY-GROUPS", kwMANDATORY_GROUPS, NULL },
        { "MAX-ACCESS", kwMAX_ACCESS, NULL },
        { "MIN-ACCESS", kwMIN_ACCESS, NULL },
        { "MODULE", kwMODULE, NULL },
        { "MODULE-COMPLIANCE", kwMODULE_COMPLIANCE, NULL },
        { "MODULE-IDENTITY", kwMODULE_IDENTITY, NULL },
        { "NOTIFICATION-GROUP", kwNOTIFICATION_GROUP, NULL },
        { "NOTIFICATION-TYPE", kwNOTIFICATION_TYPE, NULL },
        { "NOTIFICATIONS", kwNOTIFICATIONS, NULL },
        { "OBJECT", kwOBJECT, NULL },
        { "OBJECT-GROUP", kwOBJECT_GROUP, NULL },
        { "OBJECT-IDENTITY", kwOBJECT_IDENTITY, NULL },
        { "OBJECT-TYPE", kwOBJECT_TYPE, NULL },
        { "OBJECTS", kwOBJECTS, NULL },
        { "OCTET", kwOCTET, NULL },
        { "OF", kwOF, NULL },
        { "Opaque", kwOPAQUE, NULL },
        { "ORGANIZATION", kwORGANIZATION, NULL },
        { "PRODUCT-RELEASE", kwPRODUCT_RELEASE, NULL },
        { "REFERENCE", kwREFERENCE, NULL },
        { "REVISION", kwREVISION, NULL },
        { "SEQUENCE", kwSEQUENCE, NULL },
        { "SIZE", kwSIZE, NULL },
        { "STATUS", kwSTATUS, NULL },
        { "STRING", kwSTRING, NULL },
        { "SUPPORTS", kwSUPPORTS, NULL },
        { "SYNTAX", kwSYNTAX, NULL },
        { "TEXTUAL-CONVENTION", kwTEXTUAL_CONVENTION, NULL },
        { "TimeTicks", kwTIMETICKS, NULL },
        { "UNITS", kwUNITS, NULL },
        { "Unsigned32", kwUNSIGNED32, NULL },
        { "VARIATION", kwVARIATION, NULL },


Expires 1/30/1997                                              [Page 22]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        { "WRITE-SYNTAX", kwWRITE_SYNTAX, NULL }
};

/* number of keywords */
USHORT cKw = sizeof(kwNa)/sizeof(KEYWORDNAME);


/** printTokType - print type of a token
*
* call with:
*   iTokType - type of token
*
*/
    VOID
#ifdef __STDC__
printTokType(INT iTokType)
#else
printTokType(iTokType)
    INT iTokType;
#endif /* __STDC__ */
{
    /* check if in a file */
    if ((yylval.usval.loc.ulLineNo > 0L) &&
            (yylval.usval.loc.pszFn != NULL)) {

        /* output in format for editors */

        /* check if column valid */
        if (yylval.usval.loc.usColNo != 0) {
            /* print out file name, line and column number */
            fprintf(fhOut, "%s(%lu,%u): ",
                   yylval.usval.loc.pszFn,
                   yylval.usval.loc.ulLineNo,
                   yylval.usval.loc.usColNo);
        } else {
            /* print out just file name and line */
            fprintf(fhOut, "%s(%lu): ",
                   yylval.usval.loc.pszFn,
                   yylval.usval.loc.ulLineNo);
        }
    }

    fprintf(fhOut, "T: (%d) ", iTokType);
    switch(iTokType) {
    case kwACCESS:
        fprintf(fhOut, "ACCESS\n");
        break;

    case kwAGENT_CAPABILITIES:
        fprintf(fhOut, "AGENT_CAPABILITIES\n");
        break;


Expires 1/30/1997                                              [Page 23]


Draft                 SNMPv2 Lexical Specification         July 30, 1996



    case kwAUGMENTS:
        fprintf(fhOut, "AUGMENTS\n");
        break;

    case kwBEGIN:
        fprintf(fhOut, "BEGIN\n");
        break;

    case kwBITS:
        fprintf(fhOut, "BITS\n");
        break;

    case kwCONTACT_INFO:
        fprintf(fhOut, "CONTACT_INFO\n");
        break;

    case kwCOUNTER32:
        fprintf(fhOut, "COUNTER32\n");
        break;

    case kwCOUNTER64:
        fprintf(fhOut, "COUNTER64\n");
        break;

    case kwCREATION_REQUIRES:
        fprintf(fhOut, "CREATION_REQUIRES\n");
        break;

    case kwDEFINITIONS:
        fprintf(fhOut, "DEFINITIONS\n");
        break;

    case kwDEFVAL:
        fprintf(fhOut, "DEFVAL\n");
        break;

    case kwDESCRIPTION:
        fprintf(fhOut, "DESCRIPTION\n");
        break;

    case kwDISPLAY_HINT:
        fprintf(fhOut, "DISPLAY_HINT\n");
        break;

    case kwEND:
        fprintf(fhOut, "END\n");
        break;

    case kwFROM:
        fprintf(fhOut, "FROM\n");


Expires 1/30/1997                                              [Page 24]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        break;

    case kwGAUGE32:
        fprintf(fhOut, "GAUGE32\n");
        break;

    case kwGROUP:
        fprintf(fhOut, "GROUP\n");
        break;

    case kwIDENTIFIER:
        fprintf(fhOut, "IDENTIFIER\n");
        break;

    case kwIMPLIED:
        fprintf(fhOut, "IMPLIED\n");
        break;

    case kwIMPORTS:
        fprintf(fhOut, "IMPORTS\n");
        break;

    case kwINCLUDES:
        fprintf(fhOut, "INCLUDES\n");
        break;

    case kwINDEX:
        fprintf(fhOut, "INDEX\n");
        break;

    case kwINTEGER:
        fprintf(fhOut, "INTEGER\n");
        break;

    case kwINTEGER32:
        fprintf(fhOut, "INTEGER32\n");
        break;

    case kwIPADDRESS:
        fprintf(fhOut, "IPADDRESS\n");
        break;

    case kwLAST_UPDATED:
        fprintf(fhOut, "LAST_UPDATED\n");
        break;

    case kwMANDATORY_GROUPS:
        fprintf(fhOut, "MANDATORY_GROUPS\n");
        break;

    case kwMAX_ACCESS:


Expires 1/30/1997                                              [Page 25]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        fprintf(fhOut, "MAX_ACCESS\n");
        break;

    case kwMIN_ACCESS:
        fprintf(fhOut, "MIN_ACCESS\n");
        break;

    case kwMODULE:
        fprintf(fhOut, "MODULE\n");
        break;

    case kwMODULE_COMPLIANCE:
        fprintf(fhOut, "MODULE_COMPLIANCE\n");
        break;

    case kwMODULE_IDENTITY:
        fprintf(fhOut, "MODULE_IDENTITY\n");
        break;

    case kwNOTIFICATION_GROUP:
        fprintf(fhOut, "NOTIFICATION_GROUP\n");
        break;

    case kwNOTIFICATION_TYPE:
        fprintf(fhOut, "NOTIFICATION_TYPE\n");
        break;

    case kwNOTIFICATIONS:
        fprintf(fhOut, "NOTIFICATIONS\n");
        break;

    case kwOBJECT:
        fprintf(fhOut, "OBJECT\n");
        break;

    case kwOBJECT_GROUP:
        fprintf(fhOut, "OBJECT_GROUP\n");
        break;

    case kwOBJECT_IDENTITY:
        fprintf(fhOut, "OBJECT_IDENTITY\n");
        break;

    case kwOBJECT_TYPE:
        fprintf(fhOut, "OBJECT_TYPE\n");
        break;

    case kwOBJECTS:
        fprintf(fhOut, "OBJECTS\n");
        break;



Expires 1/30/1997                                              [Page 26]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


    case kwOCTET:
        fprintf(fhOut, "OCTET\n");
        break;

    case kwOF:
        fprintf(fhOut, "OF\n");
        break;

    case kwOPAQUE:
        fprintf(fhOut, "OPAQUE\n");
        break;

    case kwORGANIZATION:
        fprintf(fhOut, "ORGANIZATION\n");
        break;

    case kwPRODUCT_RELEASE:
        fprintf(fhOut, "PRODUCT_RELEASE\n");
        break;

    case kwREFERENCE:
        fprintf(fhOut, "REFERENCE\n");
        break;

    case kwREVISION:
        fprintf(fhOut, "REVISION\n");
        break;

    case kwSEQUENCE:
        fprintf(fhOut, "SEQUENCE\n");
        break;

    case kwSIZE:
        fprintf(fhOut, "SIZE\n");
        break;

    case kwSTATUS:
        fprintf(fhOut, "STATUS\n");
        break;

    case kwSTRING:
        fprintf(fhOut, "STRING\n");
        break;

    case kwSUPPORTS:
        fprintf(fhOut, "SUPPORTS\n");
        break;

    case kwSYNTAX:
        fprintf(fhOut, "SYNTAX\n");
        break;


Expires 1/30/1997                                              [Page 27]


Draft                 SNMPv2 Lexical Specification         July 30, 1996



    case kwTEXTUAL_CONVENTION:
        fprintf(fhOut, "TEXTUAL_CONVENTION\n");
        break;

    case kwTIMETICKS:
        fprintf(fhOut, "TIMETICKS\n");
        break;

    case kwUNITS:
        fprintf(fhOut, "UNITS\n");
        break;

    case kwUNSIGNED32:
        fprintf(fhOut, "UNSIGNED32\n");
        break;

    case kwVARIATION:
        fprintf(fhOut, "VARIATION\n");
        break;

    case kwWRITE_SYNTAX:
        fprintf(fhOut, "WRITE_SYNTAX\n");
        break;

    case chLCB:
        fprintf(fhOut, "LCB\n");
        break;

    case chRCB:
        fprintf(fhOut, "RCB\n");
        break;

    case chLPR:
        fprintf(fhOut, "LPR\n");
        break;

    case chRPR:
        fprintf(fhOut, "RPR\n");
        break;

    case chSEMI:
        fprintf(fhOut, "SEMI\n");
        break;

    case chCOMMA:
        fprintf(fhOut, "COMMA\n");
        break;

    case chMINUS:
        fprintf(fhOut, "MINUS\n");


Expires 1/30/1997                                              [Page 28]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


        break;

    case chDOT:
        fprintf(fhOut, "DOT\n");
        break;

    case chOR:
        fprintf(fhOut, "OR\n");
        break;

    case tokDOTDOT:
        fprintf(fhOut, "DOTDOT\n");
        break;

    case tokIS:
        fprintf(fhOut, "IS\n");
        break;

    case tokUCNAME:
        /* name starting with uppercase letter */
        fprintf(fhOut, "UCNAME - ");
        if (yylval.strval.pStr == NULL)
            fprintf(fhOut, "NULL ptr\n");
        else if (yylval.strval.pStr->pszVal == NULL)
            fprintf(fhOut, "Value is NULL ptr\n");
        else
            fprintf(fhOut, "\"%s\"\n",
                    yylval.strval.pStr->pszVal);
        break;

    case tokLCNAME:
        /* name starting with lowercase letter */
        fprintf(fhOut, "LCNAME - ");
        if (yylval.strval.pStr == NULL)
            fprintf(fhOut, "NULL ptr\n");
        else if (yylval.strval.pStr->pszVal == NULL)
            fprintf(fhOut, "Value is NULL ptr\n");
        else
            fprintf(fhOut, "\"%s\"\n",
                    yylval.strval.pStr->pszVal);
        break;

    case tokSTRING:
        /* string */
        fprintf(fhOut, "STRING - ");
        if (yylval.strval.pStr == NULL)
            fprintf(fhOut, "NULL ptr\n");
        else if (yylval.strval.pStr->pszVal == NULL)
            fprintf(fhOut, "Value is NULL ptr\n");
        else
            fprintf(fhOut, "\"%s\"\n",


Expires 1/30/1997                                              [Page 29]


Draft                 SNMPv2 Lexical Specification         July 30, 1996


                    yylval.strval.pStr->pszVal);
        break;

    case tokNUMBER:
        fprintf(fhOut, "NUMBER, value %lu\n",
               yylval.ulval.ul);
        break;

    case tokBSTR:
        /* bit string */
        fprintf(fhOut, "BSTR - ");
        if (yylval.strval.pStr == NULL)
            fprintf(fhOut, "NULL ptr\n");
        else if (yylval.strval.pStr->pszVal == NULL)
            fprintf(fhOut, "Value is NULL ptr\n");
        else
            fprintf(fhOut, "'%s'B\n",
                    yylval.strval.pStr->pszVal);
        break;

    case tokHSTR:
        /* hex string */
        fprintf(fhOut, "HSTR - ");
        if (yylval.strval.pStr == NULL)
            fprintf(fhOut, "NULL ptr\n");
        else if (yylval.strval.pStr->pszVal == NULL)
            fprintf(fhOut, "Value is NULL ptr\n");
        else
            fprintf(fhOut, "'%s'H\n",
                    yylval.strval.pStr->pszVal);
        break;

    default:
        fprintf(fhOut, "unknown type %d\n", iTokType);
        break;
    }

} /* printTokType */


/* end of file: v2c-sc.c */












Expires 1/30/1997                                              [Page 30]


Draft                 SNMPv2 Lexical Specification         July 30, 1996



5. References

[1]  J. Case, K. McCloghrie, M. Rose, S. Waldbusser, "Structure of
     Management Information for Version 2 of the Simple Network
     Management Protocol (SNMPv2)", RFC 1902, 01/22/1996.

[2]  J. Case, K. McCloghrie, M. Rose, S. Waldbusser, "Textual
     Conventions for Version 2 of the Simple Network Management Protocol
     (SNMPv2)", RFC 1903, 01/22/1996.

[3]  J. Case, K. McCloghrie, M. Rose, S. Waldbusser, "Conformance
     Statements for Version 2 of the Simple Network Management Protocol
     (SNMPv2)", RFC 1904, 01/22/1996.
     Management Information for version 2 of the Simple Network
     Management Protocol (SNMPv2)", RFC 1442, 05/03/1993.

[4]  Information processing systems - Open Systems Interconnection -
     Specification of Abstract Syntax Notation One (ASN.1),
     International Organization for Standardization.  International
     Standard 8824, (December, 1987).
































Expires 1/30/1997                                              [Page 31]