#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README Makefile plm-lex.l plm-manifest.h plm-parse.y
#   scope.c scope.h
# Wrapped by hays@hayshaus on Tue Apr  5 20:34:58 1994
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(7926 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X$Id: README,v 1.4 1994/04/05 20:33:58 hays Exp $
X
XAh, the wisdom of the ages...
X
XIntroduction
X------------
X
XWhat you are looking at is a basic (very basic) parser for a PL/M
Xlanguage.
X
XThe parser does nothing useful, and it isn't even a terribly wonderful
Xexample.  On the other hand, it appears that no one else has bothered
Xto publish even this much, before.
X
XHowever, the parser does recognize a language very like PL/M-86,
XPL/M-286, or PL/M-386, as best we can determine.
X
XAll the information used to derive this parser comes from published
Xmanuals, sold to the public.  No proprietary information, trade
Xsecrets, patented information, corporate assets, or skulduggery was
Xused to develop this parser.  Neither of the authors has ever seen the
Xsource to a working PL/M compiler (or, for that matter, to a
Xnon-working PL/M compiler).
X
XImplementation Limits
X---------------------
X
XThis PL/M parser was developed and tested on a 486DX2/66 clone PC
Xrunning Linux.  The C code is written for an ANSI-compliant C
Xcompiler; GCC was used in our testing.  Also, flex and bison were
Xused, not lex and yacc.  Paul Vixie's comp.sources.unix implementation
Xof AVL trees was used to implement symbol table lookups.
X
XYou should expect some problems if you plan on building this parser
Xwith a K&R style C compiler.  Using yacc and/or lex may be
Xproblematic, as well.
X
XThis parser does not support any of the "dollar" directives of a
Xproper PL/M compiler.  In fact, it will croak with the helpful message
X"parse error".  Thus, implementing include files and compiler
Xdirectives is left as an exercise for the reader.
X
XThe macro facility (aka "literally" declarations) depends on the
Xlexical analysis skeleton allowing multiple characters of push-back on
Xthe input stream.  This is a very, very poor assumption, but, with
Xflex, at least, workable for this example.  A real PL/M compiler would
Xallow literals of unlimited length.  To find the offending code, grep
Xfor the string "very weak" in the file "plm-lex.l".
X
XNo error recovery is implemented in the parser, at all.
X
XThere are no shift-reduce conflicts, nor reduce-reduce conflicts.
X
XThere are a couple of places in the parser where similar constructs
Xcannot be distinguished, except by semantic analysis.  These are
Xmarked by appropriate comments in the parser source file.
X
XThe "scoped literal table" implementation depends on Paul Vixie's
X(paul@vix.com) public domain AVL tree code, available as
Xcomp.sources.unix Volume 27, Issue 34 (`avl-subs'), at a friendly ftp
Xsite near you.  We use "gatekeeper.dec.com".  The benefits of using
XAVL trees for a symbol table (versus, say, hashing) are not subject to
Xdiscussion.  We used the avl-subs source code because it is reliable
Xand easy to use.
X
XThis grammar has been validated against about 10,000 lines of real and
Xartificial PL/M code.
X
XPL/M Quirks
X-----------
X
XPL/M has some very interesting quirks.  For example, a value is
Xconsidered to be "true", for the purposes of an `if' test, if it is
Xodd (low bit set).  Thus, the value 0x3 is true, whereas 0x4 is not.
XThe language itself, given a boolean expression, generates the value
X0xff for true.  [This factoid doesn't affect the parser per se, but
Xdoes appear to be the main pitfall for those whose hubris leads them
Xto translate PL/M to C.]
X
XString constants can contain any ASCII value, excepting a single
Xapostrophe, a newline, or 0x81.  The latter, presumably, has something
Xto do with Kanji support.
X
XTo embed a single apostrophe in a string constant, two apostrophes may
Xbe used.  Thus, 'k''s' is a string consisting of a letter k, a single
Xapostrophe, and a letter s.  Strings are not null terminated, so our
Xexample string, 'k''s', requires just three bytes of storage.
X
XPL/M supports a macro language, of sorts, that is integrated into the
Xlanguage's declaration syntax:
X
X	declare Ford literally 'Edsel';
X	declare Mercury literally 'Ford';
X
XAfter the above declarations, any instance of the identifier "Ford"
Xwill be replaced with the string "Edsel", and any occurrence of the
Xidentifier "Mercury" will be replaced by the string "Ford", which will
Xthen be replaced by the string "Edsel".  The literal string can be
Xmore complicated, of course.  Only identifiers are subject to
Xsubstitution - substitution does not occur inside string constants.
X
XLiteral macros are parameterless, and obey the scoping rules of the
Xlanguage.  Thus, it is possible to have different values for the same
Xmacro in different, non-nested scopes.  [Exercise: Why can't you have
Xdifferent values for literals in nested scopes?]
X
XKeywords, of course, cannot be macro names, because they are not
Xallowed as variable names.
X
XPL/M allows dollar signs ("$") to be used inside keywords,
Xidentifiers, and numerical constants.  PL/M is also case insensitive.
XThus, the following two identifiers are the "same":
X
Xmy_very_own_variable_02346
X
Xm$Y_$$$VeRy_$$O$$$$$W$$$$$$N_varIABLE$$$$$$$$$$_$02$346
X
XLoverly, eh?  Obfuscated C, stand to the side.
X
XCasting in PL/M (a relatively late addition to the language) is
Xprovided by a motley assortment of functions with the same names as
Xthe basic types to which they are casting, accepting a single argument
Xof some other (or even the same) type.
X
XNote that the EBNF grammar published in what must be considered the
Xdefinitive work, _PL/M Programmer's Guide_, Intel order number
X452161-003, Appendix C, is incorrect in several respects.  If you're
Xinterested in the differences, we've preserved, as much as is
Xpossible, the production names of that EBNF in the YACCable grammar.
X
XSome known problems with the published, Appendix C, EBNF grammar:
X
X     - One of the productions is an orphan, ("scoping_statements").
X
X     - unary minus is shown as a prefix operator, and unary plus as a
X       postfix operator ("secondary").
X 
X     - Casting does not appear in the published grammar.
X
X     - Nested structures do not appear in the published grammar, and
X       the reference syntax for selecting a nested structure member
X       is also missing.
X
X     - The WORD type is missing from the "basic_type" production.
X
X     - The "initialization" production allows the initial value list
X       only after the INITIAL keyword, when, in fact, the initial value 
X       list may follow the DATA keyword, as well.
X
XOn the other hand, the precedence of the expression operators is
Xcorrect as written in the EBNF grammar, the dangling else problem is
Xnon-existent, and there are no associativity problems, as all
Xoperators associate left-to-right.
X
XTo complicate matters, the above referenced manual may be out of
Xprint.  A more recent version, which covers the PL/M-386 dialect only,
Xis _PL/M-386 Programmer's Guide_, Intel order number 611052-001.
X
XThe latter manual has some corrections, but has some introduced errors
Xin the EBNF, as well.  The problems with the unary minus and the
X"initialization" production are repaired, but the definition for a
X"binary_number" is malformed, as are the definitions for the
X"fractional_part", "string_body_element", "variable_element", and
X"if_condition" productions.
X
XWe're right, they're wrong.
X
XThe Authors
X-----------
X
XGary Funck (gary@intrepid.com) was responsible for starting this
Xeffort.  He authored the original grammar.
X
XKirk Hays (hays@ichips.intel.com) wrote the lexical analyzer and the
Xscoped literal table implementation.  He also validated and corrected
Xthe grammar, and extended it to cover documented features not
Xappearing in the published EBNF.
X
XFuture Plans
X------------
X
XIf there is enough interest (or, even if there isn't), Kirk is
Xplanning on producing a PL/M front end for the GNU compiler.  Contact
Xhim at the above Email address for further information.  Donations of
XPL/M source code of any dialect (including PL/M-80, PL/M-51, and
XPL/M-96)(yes, we already have the Kermit implementations), or a
Xwillingness to be a pre-alpha tester with code you cannot donate, are
Xsufficient grounds to contact Kirk.
X
END_OF_FILE
if test 7926 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(871 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# $Id: Makefile,v 1.3 1994/02/28 22:28:36 hays Exp $
X
XLEX=flex
XLEXFLAGS= -v
XYACC=bison
XYACCFLAGS= -y -v -d
XCFLAGS= -g
XDIST=README Makefile plm-lex.l plm-manifest.h plm-parse.y scope.c scope.h
XOBJS= plm-lex.o plm-parse.o scope.o tree.o
X#NOTE: tree.o and tree.h come from Paul Vixie's PD AVL Tree package,
X#      comp.sources.unix Volume 27, Issue 34.
X
X.y.c:
X
Xplm: $(OBJS)
X	$(CC) $(CFLAGS) -o $@ $(OBJS)
X
Xplm-parse.h: plm-parse.c
X
Xplm-lex.c: plm-lex.l
X	$(LEX) $(LEXFLAGS) -t $< > $@
X
Xplm-parse.c: plm-parse.y
X	$(YACC) $(YACCFLAGS) $< -o $@
X
Xplm-lex.o: plm-lex.c plm-manifest.h plm-parse.h scope.h
X 
Xplm-parse.o: plm-parse.c plm-manifest.h scope.h
X
Xscope.o: scope.c tree.h scope.h
X
Xclean:
X	rm -f plm-parse.c plm-parse.h plm-parse.output \
X	plm-*.o scope.o lex.backtrack tmp *~ plm-lex.c core plm \
X	plm.shar
X
Xsource:
X	$(CO) $(DIST)
X
Xdist: source
X	shar $(DIST) > plm.shar
X
X
X
END_OF_FILE
if test 871 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'plm-lex.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'plm-lex.l'\"
else
echo shar: Extracting \"'plm-lex.l'\" \(8476 characters\)
sed "s/^X//" >'plm-lex.l' <<'END_OF_FILE'
X%{
X/* lexer for PL/M syntax.
X
X$Id: plm-lex.l,v 1.2 1994/02/28 22:24:34 hays Exp $
X
XCopyright 1994 by Kirk Hays (hays@ichips.intel.com) and Gary Funck
X(gary@intrepid.com)
X
XUSE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
XThis code is distributed in the hope that it will be useful,
Xbut without any warranty.  Further, there is no implied warranty of
Xmerchantability or fitness for a particular purpose.
X
X*/
X
X/* This file defines the syntax of PL/M. */
X
X#include <ctype.h>
X#include <string.h>
X#include "plm-manifest.h"
X#include "plm-parse.h"
X#include "scope.h"
X
Xint lineno = 1;
X
X/* forward references */
Xchar * canonical_string (char *);
Xchar * canonical_identifier (char *);
Xstatic void error (char *);
X
X%}
X
XDIGIT_STRING [0-9][0-9$]*
XA       [Aa]($)*
XB       [Bb]($)*
XC       [Cc]($)*
XD       [Dd]($)*
XE       [Ee]($)*
XF       [Ff]($)*
XG       [Gg]($)*
XH       [Hh]($)*
XI       [Ii]($)*
XL       [Ll]($)*
XM       [Mm]($)*
XN       [Nn]($)*
XO       [Oo]($)*
XP       [Pp]($)*
XQ       [Qq]($)*
XR       [Rr]($)*
XS       [Ss]($)*
XT       [Tt]($)*
XU       [Uu]($)*
XW       [Ww]($)*
XX       [Xx]($)*
XY       [Yy]($)*
X
X%%
X
X{A}{D}{D}{R}{E}{S}{S}           return ADDRESS;
X{A}{N}{D}                       return AND;
X{A}{T}                          return AT;
X{B}{A}{S}{E}{D}                 return BASED;
X{B}{Y}                          return BY;
X{B}{Y}{T}{E}                    return BYTE;
X{C}{A}{L}{L}                    return CALL;
X{C}{A}{S}{E}                    return CASE;
X{C}{A}{U}{S}{E}{I}{N}{T}{E}{R}{R}{U}{P}{T}      return CAUSE_INTERRUPT;
X{C}{H}{A}{R}{I}{N}{T}           return CHARINT;
X{D}{A}{T}{A}                    return DATA;
X{D}{E}{C}{L}{A}{R}{E}           return DECLARE;
X{D}{I}{S}{A}{B}{L}{E}           return DISABLE;
X{D}{O}                          return DO;
X{D}{W}{O}{R}{D}                 return DWORD;
X{E}{L}{S}{E}                    return ELSE;
X{E}{N}{A}{B}{L}{E}              return ENABLE;
X{E}{N}{D}                       return END;
X{E}{O}{F}                       return EOF_KW;
X{E}{X}{T}{E}{R}{N}{A}{L}        return EXTERNAL;
X{G}{O}                          return GO;
X{G}{O}{T}{O}                    return GOTO;
X{H}{A}{L}{T}                    return HALT;
X{H}{W}{O}{R}{D}                 return HWORD;
X{I}{F}                          return IF;
X{I}{N}{I}{T}{I}{A}{L}           return INITIAL_KW;
X{I}{N}{T}{E}{G}{E}{R}           return INTEGER;
X{I}{N}{T}{E}{R}{R}{U}{P}{T}     return INTERRUPT;
X{L}{A}{B}{E}{L}                 return LABEL;
X{L}{I}{T}{E}{R}{A}{L}{L}{Y}     return LITERALLY;
X{L}{O}{N}{G}{I}{N}{T}           return LONGINT;
X{M}{I}{N}{U}{S}                 return MINUS;
X{M}{O}{D}                       return MOD;
X{N}{O}{T}                       return NOT;
X{O}{F}{F}{S}{E}{T}              return OFFSET;
X{O}{R}                          return OR;
X{P}{L}{U}{S}                    return PLUS;
X{P}{O}{I}{N}{T}{E}{R}           return POINTER;
X{P}{R}{O}{C}{E}{D}{U}{R}{E}     return PROCEDURE;
X{P}{U}{B}{L}{I}{C}              return PUBLIC;
X{Q}{W}{O}{R}{D}                 return QWORD;
X{R}{E}{A}{L}                    return REAL;
X{R}{E}{E}{N}{T}{R}{A}{N}{T}     return REENTRANT;
X{R}{E}{T}{U}{R}{N}              return RETURN;
X{S}{E}{L}{E}{C}{T}{O}{R}        return SELECTOR;
X{S}{H}{O}{R}{T}{I}{N}{T}        return SHORTINT;
X{S}{T}{R}{U}{C}{T}{U}{R}{E}     return STRUCTURE;
X{T}{H}{E}{N}                    return THEN;
X{T}{O}                          return TO;
X{W}{H}{I}{L}{E}                 return WHILE;
X{W}{O}{R}{D}                    return WORD;
X{X}{O}{R}                       return XOR;
X
X[_A-Za-z][_$0-9A-Za-z]*         {
X                                 char * string;
X                                 int i;
X                                 yylval = canonical_identifier(yytext);
X                                 string = lookup_literal(yylval);
X                                 if (!string)
X                                   {
X                                     return IDENTIFIER;
X                                   }
X                                 free(yylval); 
X                                 yylval=0; /*excessive neatness*/
X                                 /* push the string back onto the input
X                                    stream - it is necessary to push 
X                                    from right to left */
X                                 for (i = strlen (string);
X                                      i >= 0;
X                                      i--) 
X                                   {
X                                     /* very weak - depends on lexical 
X                                        generator allowing sufficient
X                                        push-back */
X                                     unput (string[i]);
X                                   }
X                                }
X
X[0-9][0-9$]*(d)?                return DECIMAL_NUMBER;
X
X{DIGIT_STRING}\.({DIGIT_STRING})?([E|e][+|-]?{DIGIT_STRING})?   return FLOATING_POINT_NUMBER;
X
X[01][01$]*[bB]                  return BINARY_NUMBER;
X
X[0-9][0-9a-fA-F$]*[hH]          return HEX_NUMBER;
X
X[0-7][0-7$]*[OoQq]              return OCTAL_NUMBER;
X
X'([^'\n\201]|(''))+'            {
X                                 yylval = canonical_string(yytext); 
X                                 return STRING;
X                                }
X
X:=                              return ASSIGN_OP;
X
X[\@]                            return AT_SIGN;
X
X:                               return COLON;
X
X,                               return COMMA;
X
X[\.]                            return DOT;
X
X=                               return EQ;
X
X>=                              return GE;
X
X>                               return GT;
X
X"<="                            return LE;
X
X\(                              return LPAREN;
X
X"<"                             return LT;
X
X-                               return MINUS_SIGN;
X
X"<>"                            return NE;
X
X"+"                             return PLUS_SIGN;
X
X\)                              return RPAREN;
X
X;                               return SEMI;
X
X"/"                             return SLASH;
X
X\*                              return STAR;
X
X\f
X
X\n                              lineno++;
X
X[\t ]*
X
X"/*"                            {
X                                register int c;
X
X                                for ( ; ; )
X                                  {
X                                    while ( (c = input()) != '*' &&
X                                           c != EOF )
X                                      if (c == '\n') lineno++;
X                                      /* eat up text of comment */
X
X                                    if ( c == '*' )
X                                      {
X                                        while ( (c = input()) == '*' )
X                                          ;
X                                        if ( c == '/' )
X                                          break;    /* found the end */
X                                      }
X
X                                    if (c == '\n') lineno++;
X
X                                    if ( c == EOF )
X                                      {
X                                        error( "EOF in comment" );
X                                        break;
X                                      }
X                                  }
X                              }
X
X.
X
X%%
X
Xstatic void error (char * x) {printf (x);}
X 
X/* Strip the single quotes from a pl/m string, and
X   compress any single quote pairs to one quote.
X
X   Allocates new storage for the string.
X*/
Xchar * 
Xcanonical_string (char * s)
X{
X  int i, i_ret;
X  char * ret;
X  int len = strlen (s);
X
X  ret = malloc (len+1);
X  if (!ret)
X    return 0;
X
X  for (i = 1, i_ret = 0; i < (len-1); i++)
X    {
X      ret[i_ret++] = s[i];
X      if (s[i] == '\'')
X        {
X          i++;
X        }
X    }
X
X  ret[i_ret] = 0;
X
X  return ret;
X
X}
X
X/* Strip the dollar signs from a pl/m identifier or 
X   numeric constant, and force all alphabetic characters 
X   to lower case.
X
X   Allocates new storage for the identifier string.
X
X*/
Xchar * 
Xcanonical_identifier (char * s)
X{
X  int i, i_ret;
X  char * ret;
X  int len = strlen (s);
X
X  ret = malloc (len+1);
X  if (!ret)
X    return 0;
X
X  for (i = 0, i_ret = 0; i < len; i++)
X    {
X      if (s[i] == '$')
X        {
X          continue;
X        }
X      ret[i_ret++] = tolower (s[i]);
X    }
X
X  ret[i_ret] = 0;
X
X  return ret;
X
X}
X
X#ifdef LEX_ONLY
X
Xmain() {
X
X  for (;;)
X    yylex();
X
X}
X
X#endif
END_OF_FILE
if test 8476 -ne `wc -c <'plm-lex.l'`; then
    echo shar: \"'plm-lex.l'\" unpacked with wrong size!
fi
# end of 'plm-lex.l'
fi
if test -f 'plm-manifest.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'plm-manifest.h'\"
else
echo shar: Extracting \"'plm-manifest.h'\" \(605 characters\)
sed "s/^X//" >'plm-manifest.h' <<'END_OF_FILE'
X/* manifest constants/types for PL/M lexer/parser.
X
X$Id: plm-manifest.h,v 1.1 1994/02/28 20:54:26 hays Exp $
X
XCopyright 1994 by Kirk Hays (hays@ichips.intel.com)
X
XUSE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
XThis code is distributed in the hope that it will be useful,
Xbut without any warranty.  Further, there is no implied warranty of
Xmerchantability or fitness for a particular purpose.
X
X*/
X
Xextern int lineno;
X
X/* brute force type the value stack - this would not be appropriate in
X   a real compiler, but suits our purposes just fine */
X
Xtypedef char * CHAR_PTR;
X#define YYSTYPE CHAR_PTR
X
END_OF_FILE
if test 605 -ne `wc -c <'plm-manifest.h'`; then
    echo shar: \"'plm-manifest.h'\" unpacked with wrong size!
fi
# end of 'plm-manifest.h'
fi
if test -f 'plm-parse.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'plm-parse.y'\"
else
echo shar: Extracting \"'plm-parse.y'\" \(14574 characters\)
sed "s/^X//" >'plm-parse.y' <<'END_OF_FILE'
X/* YACC parser for PL/M syntax.
X
X$Id: plm-parse.y,v 1.1 1994/02/28 20:54:56 hays Exp $
X
XCopyright 1994 by Kirk Hays (hays@ichips.intel.com) and Gary Funck
X(gary@intrepid.com)
X
XUSE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
XThis code is distributed in the hope that it will be useful,
Xbut without any warranty.  Further, there is no implied warranty of
Xmerchantability or fitness for a particular purpose.
X
X*/
X
X/* This file defines the grammar of PL/M. */
X
X%{
X
X/*
X * YACC grammar of PL/M
X */
X#include <stdio.h>
X#include <stdlib.h>
X#include "plm-manifest.h"
X#include "scope.h"
X
Xvoid yyerror ();
X
X/* Cause the `yydebug' variable to be defined.  */
X#define YYDEBUG (1)
X
X%}
X
X%token ADDRESS AND ASSIGN_OP AT AT_SIGN BASED
X%token BINARY_NUMBER BY BYTE CALL CASE
X%token CAUSE_INTERRUPT CHARINT COLON COMMA DATA
X%token DECIMAL_NUMBER DECLARE DISABLE DO DOT
X%token DWORD ELSE ENABLE END EOF_KW EQ
X%token EXTERNAL FLOATING_POINT_NUMBER GE GO
X%token GOTO GT HALT HEX_NUMBER HWORD
X%token IDENTIFIER
X%token IF INITIAL_KW INTEGER INTERRUPT
X%token LABEL LE LITERALLY LONGINT LPAREN LT
X%token MINUS MINUS_SIGN MOD NE NOT
X%token OCTAL_NUMBER OFFSET OR PLUS PLUS_SIGN
X%token POINTER PROCEDURE PUBLIC QWORD
X%token REAL REENTRANT RETURN RPAREN SELECTOR
X%token SEMI SHORTINT SLASH STAR STRING
X%token STRUCTURE THEN TO WHILE WORD XOR
X
X
X%start compilation
X
X%%
Xactual_parameters:
X        LPAREN expression_list RPAREN
X        ;
Xadding_operator:
X        MINUS
X        | MINUS_SIGN
X        | PLUS
X        | PLUS_SIGN
X        ;
Xand_operator:
X        AND
X        ;
Xarithmetic_expression:
X        term
X        | arithmetic_expression adding_operator term
X        ;
Xarray_specifier:
X        explicit_dimension
X        | implicit_dimension
X        ;
Xassignment_statement:
X        left_part EQ expression SEMI
X        ;
Xbase_specifier:
X        IDENTIFIER
X        | IDENTIFIER DOT IDENTIFIER
X        ;
Xbasic_statement:
X        assignment_statement
X        | call_statement
X        | goto_statement
X        | microprocessor_dependent_statement
X        | null_statement
X        | return_statement
X        ;
Xbasic_type:
X        ADDRESS
X        | BYTE
X        | CHARINT
X        | DWORD
X        | HWORD
X        | INTEGER
X        | LONGINT
X        | OFFSET
X        | POINTER
X        | QWORD
X        | REAL
X        | SELECTOR
X        | SHORTINT
X        | WORD
X        ;
Xbound_expression:
X        expression
X        ;
Xby_part:
X        BY step_expression
X        ;
Xcall_statement:
X        CALL simple_variable SEMI
X        | CALL simple_variable actual_parameters SEMI
X        ;
Xcast_type:
X        basic_type
X        ;
Xcause_interrupt_statement:
X        CAUSE_INTERRUPT LPAREN integer_constant RPAREN SEMI
X        ;
Xcompilation:
X        module
X        | module EOF_KW
X        ;
Xconditional_clause:
X        if_condition true_unit
X        | if_condition true_element ELSE false_element
X        ;
Xconstant:
X        STRING
X        | numeric_constant
X        ;
Xconstant_attribute:
X        DATA
X        ;
Xconstant_list:
X        constant
X        | constant_list COMMA constant
X        ;
Xdeclaration:
X        declare_statement
X        | procedure_definition
X        ;
Xdeclaration_sequence:
X        declaration
X        | declaration_sequence declaration
X        ;
Xdeclare_element:
X        factored_element
X        | unfactored_element
X        ;
Xdeclare_element_list:
X        declare_element
X        | declare_element_list COMMA declare_element
X        ;
Xdeclare_statement:
X        DECLARE declare_element_list SEMI
X        ;
Xdisable_statement:
X        DISABLE SEMI
X        ;
Xdo_block:
X        do_case_block
X        | do_while_block
X        | iterative_do_block
X        | simple_do_block
X        ;
Xdo_case_block:
X        do_case_statement ending
X        | do_case_statement unit_sequence ending
X        ;
Xdo_case_statement:
X        DO CASE expression SEMI {
X                                 push_scope();
X                                }
X        ;
Xdo_while_block:
X        do_while_statement ending
X        | do_while_statement unit_sequence ending
X        ;
Xdo_while_statement:
X        DO WHILE expression SEMI {
X                                  push_scope();
X                                 }
X        ;
Xembedded_assignment:
X        variable_reference ASSIGN_OP logical_expression
X        ;
Xenable_statement:
X        ENABLE SEMI
X        ;
Xend_statement:
X        END opt_identifier SEMI {
X                                 pop_scope();
X                                }
X        ;
Xending:
X        end_statement
X        | label_definition_sequence end_statement
X        ;
Xexplicit_dimension:
X        LPAREN numeric_constant RPAREN
X        ;
Xexpression:
X        embedded_assignment
X        | logical_expression
X        ;
Xexpression_list:
X        expression
X        | expression_list COMMA expression
X        ;
Xfactored_element:
X        factored_label_element
X        | factored_variable_element
X        ;
X/*
X * factored_label_element doesn't permit based variables,
X * yet factored_variable_element does.  This can't be disambiguated
X * syntactically.  Thus, the factored_label element will have to
X * make the proper semantic checks to make the sure that the
X * variable_name_specifier_list is in fact an identifier_list.
X */ 
Xfactored_label_element:
X        LPAREN variable_name_specifier_list RPAREN LABEL opt_public_or_external
X        ;
Xfactored_member:
X        LPAREN member_name_list RPAREN opt_explicit_dimension variable_type
X        ;
Xfactored_variable_element:
X        LPAREN variable_name_specifier_list RPAREN opt_explicit_dimension variable_type opt_variable_attributes
X        ;
Xfalse_element:
X        unit
X        ;
Xformal_parameter:
X        IDENTIFIER
X        ;
Xformal_parameter_list:
X        formal_parameter
X        | formal_parameter_list COMMA formal_parameter
X        ;
Xformal_parameter_specifier:
X        LPAREN formal_parameter_list RPAREN
X        ;
Xgo_to:
X        GOTO
X        | GO TO
X        ;
Xgoto_statement:
X        go_to IDENTIFIER SEMI
X        ;
Xhalt_statement:
X        HALT SEMI
X        ;
Xid_colon:
X        IDENTIFIER COLON
X        ;
Xif_condition:
X        IF expression THEN
X        ;
Ximplicit_dimension:
X        LPAREN STAR RPAREN
X        ;
Xindex_part:
X        index_variable EQ start_expression
X        ;
Xindex_variable:
X        simple_variable
X        ;
Xinitial_value:
X        expression
X        ;
Xinitial_value_list:
X        initial_value
X        | initial_value_list COMMA initial_value
X        ;
Xinitialization:
X        DATA LPAREN initial_value_list RPAREN
X        | INITIAL_KW LPAREN initial_value_list RPAREN
X        ;
Xinteger_constant:
X        BINARY_NUMBER
X        | DECIMAL_NUMBER
X        | HEX_NUMBER
X        | OCTAL_NUMBER
X        ;
Xinterrupt:
X        INTERRUPT opt_interrupt_number
X        ;
Xinterrupt_number:
X        integer_constant
X        ;
Xiterative_do_block:
X        iterative_do_statement ending
X        | iterative_do_statement unit_sequence ending
X        ;
Xiterative_do_statement:
X        DO index_part to_part opt_by_part SEMI {
X                                                push_scope();
X                                               }
X        ;
Xlabel_definition:
X        id_colon
X        ;
Xlabel_definition_sequence:
X        label_definition
X        | label_definition_sequence label_definition
X        ;
Xlabel_element:
X        IDENTIFIER LABEL opt_public_or_external
X        ;
Xleft_part:
X        variable_reference_list
X        ;
Xliteral_element:
X        IDENTIFIER LITERALLY STRING     {
X                                          enter_literal ($1, $3);
X                                        }
X        ;
Xlocation_reference:
X        AT_SIGN variable_reference
X        | AT_SIGN LPAREN constant_list RPAREN
X        | DOT variable_reference
X        | DOT LPAREN constant_list RPAREN
X        ;
Xlocator:
X        AT LPAREN expression RPAREN
X        ;
Xlocator_initialization:
X        locator
X        | initialization
X        | locator initialization
X        ;
Xlogical_expression:
X        logical_factor
X        | logical_expression or_operator logical_factor
X        ;
Xlogical_factor:
X        logical_secondary
X        | logical_factor and_operator logical_secondary
X        ;
Xlogical_primary:
X        arithmetic_expression
X        | arithmetic_expression relation_operator arithmetic_expression
X        ;
Xlogical_secondary:
X        logical_primary
X        | NOT logical_primary
X        ;
Xmember_element:
X        structure_type
X        | factored_member
X        | unfactored_member
X        ;
Xmember_element_list:
X        member_element
X        | member_element_list COMMA member_element
X        ;
Xmember_name:
X        IDENTIFIER
X        ;
Xmember_name_list:
X        member_name
X        | member_name_list COMMA member_name
X        ;
Xmember_specifier:
X        DOT member_name 
X        | DOT member_name subscript
X        ;
Xmember_specifier_sequence:
X        member_specifier_sequence member_specifier
X        | member_specifier
X        ;
Xmicroprocessor_dependent_statement:
X        cause_interrupt_statement
X        | disable_statement
X        | enable_statement
X        | halt_statement
X        ;
Xmodule:
X        module_name COLON simple_do_block
X        ;
Xmodule_name:
X        IDENTIFIER
X        ;
Xmultiplying_operator:
X        MOD
X        | SLASH
X        | STAR
X        ;
Xnull_statement:
X        SEMI
X        ;
Xnumeric_constant:
X        FLOATING_POINT_NUMBER
X        | integer_constant
X        ;
Xopt_array_specifier:
X        /* empty */
X        | array_specifier
X        ;
Xopt_by_part:
X        /* empty */
X        | by_part
X        ;
Xopt_explicit_dimension:
X        /* empty */
X        | explicit_dimension
X        ;
Xopt_formal_parameter_specifier:
X        /* empty */
X        | formal_parameter_specifier
X        ;
Xopt_identifier:
X        /* empty */
X        | IDENTIFIER
X        ;
Xopt_interrupt_number:
X        /* empty */
X        | interrupt_number
X        ;
Xopt_procedure_attribute_sequence:
X        /* empty */
X        | procedure_attribute_sequence
X        ;
Xopt_procedure_type:
X        /* empty */
X        | procedure_type
X        ;
Xopt_public_or_external:
X        /* empty */
X        | EXTERNAL
X        | PUBLIC
X        ;
Xopt_variable_attributes:
X        /* empty */
X        | variable_attributes
X        ;
Xor_operator:
X        OR
X        | XOR
X        ;
Xprimary:
X        constant
X        | location_reference
X        | subexpression
X        | variable_reference
X        ;
Xprocedure_attribute:
X        EXTERNAL
X        | PUBLIC
X        | REENTRANT
X        | interrupt PUBLIC
X        | interrupt EXTERNAL
X        ;
Xprocedure_attribute_sequence:
X        procedure_attribute
X        | procedure_attribute_sequence procedure_attribute
X        ;
Xprocedure_definition:
X        procedure_statement ending
X        | procedure_statement declaration_sequence ending
X        | procedure_statement unit_sequence ending
X        | procedure_statement declaration_sequence unit_sequence ending
X        ;
Xprocedure_statement:
X        id_colon PROCEDURE opt_formal_parameter_specifier opt_procedure_type opt_procedure_attribute_sequence SEMI
X                {
X                 push_scope();
X                }       
X        ;
Xprocedure_type:
X        basic_type
X        ;
Xrelation_operator:
X        EQ
X        | GE
X        | GT
X        | LE
X        | LT
X        | NE
X        ;
Xreturn_statement:
X        typed_return
X        | untyped_return
X        ;
Xsecondary:
X        primary
X        | unary_sign primary
X        ;
Xsimple_do_block:
X        simple_do_statement ending
X        | simple_do_statement unit_sequence ending
X        | simple_do_statement declaration_sequence ending
X        | simple_do_statement declaration_sequence unit_sequence ending
X        ;
Xsimple_do_statement:
X        DO SEMI {
X                 push_scope();
X                }
X        ;
Xsimple_variable:
X        IDENTIFIER
X        | IDENTIFIER DOT IDENTIFIER
X        ;
Xstart_expression:
X        expression
X        ;
Xstep_expression:
X        expression
X        ;
Xstructure_type:
X        STRUCTURE LPAREN member_element_list RPAREN
X        ;
Xsubexpression:
X        LPAREN expression RPAREN
X        ;
Xsubscript:
X        LPAREN expression RPAREN
X        ;
Xsubscript_or_actual_parameters:
X        LPAREN expression_list RPAREN
X        ;
Xterm:
X        secondary
X        | term multiplying_operator secondary
X        ;
Xto_part:
X        TO bound_expression
X        ;
Xtrue_element:
X        true_statement
X        | label_definition_sequence true_statement
X        ;
Xtrue_statement:
X        do_block
X        | basic_statement
X        ;
Xtrue_unit:
X        unit
X        ;
Xtyped_return:
X        RETURN expression SEMI
X        ;
Xunary_minus:
X        MINUS_SIGN
X        ;
Xunary_plus:
X        PLUS_SIGN
X        ;
Xunary_sign:
X        unary_minus
X        | unary_plus
X        ;
Xunfactored_element:
X        label_element
X        | literal_element
X        | variable_element
X        ;
Xunfactored_member:
X        member_name opt_explicit_dimension variable_type
X        ;
Xunit:
X        unit_element
X        | label_definition_sequence unit_element
X        ;
Xunit_element:
X        basic_statement
X        | conditional_clause
X        | do_block
X        ;
Xunit_sequence:
X        unit
X        | unit_sequence unit
X        ;
Xuntyped_return:
X        RETURN SEMI
X        ;
Xvariable_attributes:
X        EXTERNAL constant_attribute
X        | EXTERNAL
X        | PUBLIC locator_initialization
X        | PUBLIC
X        | locator_initialization
X        ;
Xvariable_element:
X        variable_name_specifier opt_array_specifier variable_type opt_variable_attributes
X        ;
Xvariable_name_specifier:
X        IDENTIFIER
X        | IDENTIFIER BASED base_specifier
X        ;
Xvariable_name_specifier_list:
X        variable_name_specifier
X        | variable_name_specifier_list COMMA variable_name_specifier
X        ;
X/*
X * Variable references may be either data references or function
X * references.  Syntactically, they appear to be the same, each
X * is followed by a parenthesized comma separated list of expressions.
X *
X * A function reference, of course, cannot have the trailing list of 
X * member specifiers - semantic checking will catch this.
X */
Xvariable_reference:
X        IDENTIFIER
X        | IDENTIFIER member_specifier_sequence
X        | cast_type subscript
X        | IDENTIFIER subscript_or_actual_parameters
X        | IDENTIFIER subscript_or_actual_parameters member_specifier_sequence
X        ;
Xvariable_reference_list:
X        variable_reference
X        | variable_reference_list COMMA variable_reference
X        ;
Xvariable_type:
X        basic_type
X        | structure_type
X        ;
X
X%%
X
Xvoid
Xyyerror(char * s)
X{
X  fprintf (stderr, "error at line %d: %s\n", lineno, s);
X}
X
Xmain() 
X{
X  init_scope();
X  return yyparse();
X}
END_OF_FILE
if test 14574 -ne `wc -c <'plm-parse.y'`; then
    echo shar: \"'plm-parse.y'\" unpacked with wrong size!
fi
# end of 'plm-parse.y'
fi
if test -f 'scope.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'scope.c'\"
else
echo shar: Extracting \"'scope.c'\" \(3455 characters\)
sed "s/^X//" >'scope.c' <<'END_OF_FILE'
X/* literal symbol table for PL/M.
X
X$Id: scope.c,v 1.1 1994/02/28 20:55:56 hays Exp $
X
XCopyright 1994 by Kirk Hays (hays@ichips.intel.com)
X
XUSE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
XThis code is distributed in the hope that it will be useful,
Xbut without any warranty.  Further, there is no implied warranty of
Xmerchantability or fitness for a particular purpose.
X
XThis code implements a scoped symbol table.  It depends on Paul
XVixie's PD AVL Tree code, distributed in comp.sources.unix, Volume 27,
XIssue 34.
X
X*/
X
X#include <stdlib.h>
X#include <stdio.h>
X#include "tree.h"
X#include "scope.h"
X
Xtypedef struct lit_table_stack_t_elem {
X  struct lit_table_stack_t_elem *next;
X  tree * literal_table;
X} lit_table_stack_t;
X
X/* innermost scope for scope list */
Xstatic lit_table_stack_t  *lit_table_stack;
X
Xtypedef struct {
X  char * identifier;
X  char * string;
X} literal_t;
X
X/* static forward references */
Xstatic void new_scope (lit_table_stack_t *);
Xstatic int literal_compar (literal_t *, literal_t *);
Xstatic void literal_error (literal_t *);
Xstatic void literal_t_delete (literal_t *);
X
X/* lookup an identifier in the scoped symbol table */
Xchar *
Xlookup_literal (char * identifier)
X{
X  literal_t * datum;
X  literal_t * node;
X  lit_table_stack_t * scope;
X  
X  node = alloca (sizeof (literal_t));
X  node->identifier = identifier;
X  
X  for (scope = lit_table_stack; scope; scope=scope->next)
X    {
X      datum = tree_srch(&(scope->literal_table), literal_compar, node);
X      if (datum)
X        {
X          return datum->string;
X        }
X    }
X  
X  return 0;
X  
X}
X
X/* enter an identifier in the current scoping level */
Xvoid
Xenter_literal (char * identifier, char * string)
X{  
X  literal_t * datum;
X  
X  datum = malloc (sizeof (literal_t));
X  datum->identifier = identifier;
X  datum->string = string;
X  tree_add (&(lit_table_stack->literal_table),
X            literal_compar,
X            datum,
X            literal_error);
X}
X
X/* increase scope depth by one level - creates a new symbol table
X   for the current scope */
Xvoid 
Xpush_scope (void)
X{
X  new_scope (lit_table_stack);
X}
X
X/* remove the innermost scope of the symbol table - releases all
X   allocated storage for that scope */
Xvoid 
Xpop_scope (void)
X{
X  lit_table_stack_t * p;
X  
X  p = lit_table_stack;
X  lit_table_stack = lit_table_stack->next;
X  tree_mung (&(p->literal_table), literal_t_delete);
X  if (p->literal_table)
X    {
X      free(p->literal_table);
X    }
X  free(p);
X}
X
X/* initialize this module, creating the outermost scope */
Xvoid 
Xinit_scope (void) 
X{
X  new_scope (0);
X}
X
X/* work procedure to create a new scope */
Xstatic void 
Xnew_scope (lit_table_stack_t * next)
X{
X  lit_table_stack = malloc (sizeof (lit_table_stack_t));
X  lit_table_stack->next = next;
X  tree_init (&(lit_table_stack->literal_table));
X}
X
X/* internal procedure to free storage when a symbol table entry is
X   deleted */
Xstatic 
Xvoid literal_t_delete (literal_t * datum)
X{
X  free (datum->string);
X  free (datum->identifier);
X}
X
X/* internal procedure to determine the match order for two symbol
X   table entries */
X
Xstatic int 
Xliteral_compar (literal_t * left, literal_t * right)
X{
X  return strcmp (left->identifier, right->identifier);
X}
X
X/* assertion procedure to assure that duplicate literals are never
X   added at a single scoping level */
X
Xstatic void 
Xliteral_error (literal_t * in_error)
X{
X  fprintf (stderr, 
X	   "literal table error - attempt to enter same identifier twice\n");
X  exit (255);
X}
X
X
END_OF_FILE
if test 3455 -ne `wc -c <'scope.c'`; then
    echo shar: \"'scope.c'\" unpacked with wrong size!
fi
# end of 'scope.c'
fi
if test -f 'scope.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'scope.h'\"
else
echo shar: Extracting \"'scope.h'\" \(690 characters\)
sed "s/^X//" >'scope.h' <<'END_OF_FILE'
X/* public interfaces for literal symbol table for PL/M.
X
X$Id: scope.h,v 1.1 1994/02/28 20:56:13 hays Exp $
X
XCopyright 1994 by Kirk Hays (hays@ichips.intel.com)
X
XUSE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED.
XThis code is distributed in the hope that it will be useful,
Xbut without any warranty.  Further, there is no implied warranty of
Xmerchantability or fitness for a particular purpose.
X
XThis code implements a scoped symbol table.  It depends on Paul
XVixie's PD AVL Tree code, distributed in comp.sources.unix, Volume 27,
XIssue 34.
X
X*/
X
Xchar * lookup_literal (char *);
Xvoid enter_literal (char *, char *);
Xvoid push_scope (void);
Xvoid pop_scope (void);
Xvoid init_scope (void);
END_OF_FILE
if test 690 -ne `wc -c <'scope.h'`; then
    echo shar: \"'scope.h'\" unpacked with wrong size!
fi
# end of 'scope.h'
fi
echo shar: End of shell archive.
exit 0
