This is read.c in view mode; [Download] [Up]
/**************************************************************************** ** *A read.c GAP source Martin Schoenert ** *H @(#)$Id: read.c,v 3.27 1994/01/07 09:45:44 werner Rel $ ** *Y Copyright 1990-1992, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany ** ** This module contains the functions to read expressions and statements. ** *H $Log: read.c,v $ *H Revision 3.27 1994/01/07 09:45:44 werner *H fixed ExitKernel() call in RdAtom() when reading an integer *H *H Revision 3.26 1993/02/12 17:50:28 martin *H added large permutations *H *H Revision 3.25 1993/02/12 10:45:46 martin *H changed 'RdVar' to surpress warnings for recursive functions *H *H Revision 3.24 1993/02/04 10:51:10 martin *H changed 'T_STRING' to 'T_RECNAME' and general ranges *H *H Revision 3.23 1992/12/08 11:40:54 martin *H added '<list>{<positions>}' *H *H Revision 3.22 1992/04/28 14:12:57 martin *H changed a few things to silence GCC *H *H Revision 3.21 1992/01/20 14:31:53 martin *H raised the number of statements in a block to 1024 *H *H Revision 3.20 1992/01/08 13:01:26 martin *H fixed a minor bug *H *H Revision 3.19 1992/01/08 11:12:27 martin *H changed 'RdVar' to correctly parse 'a.("a") = 1' *H *H Revision 3.18 1992/01/02 11:09:39 martin *H added '<rec>.(<name>)' construct *H *H Revision 3.17 1991/12/04 15:28:40 martin *H fixed 'RdPerm' to avoid memory faults after syntax errors *H *H Revision 3.16 1991/09/09 10:17:48 martin *H fixed 'RdAtom' to protect large integers *H *H Revision 3.15 1991/05/22 10:04:57 martin *H fixed warnings so they do not shaddow errors *H *H Revision 3.14 1991/04/30 16:12:40 martin *H initial revision under RCS *H *H Revision 3.13 1991/04/16 12:00:00 martin *H improved reading of large integers *H *H Revision 3.12 1991/04/10 12:00:00 martin *H added warning for 'for <undef var> in ...' *H *H Revision 3.11 1991/01/30 12:00:00 martin *H improved the permutation package considerably *H *H Revision 3.10 1991/01/23 12:00:00 martin *H fixed '1 -> b' yields 'segmentation fault' *H *H Revision 3.9 1991/01/21 12:00:00 martin *H fixed '1 ->' yields 'bus error, core dumped' *H *H Revision 3.8 1991/01/15 12:00:00 martin *H fixed 'x ->' yields 'warning, undefined variable' *H *H Revision 3.7 1990/12/27 12:00:00 martin *H changed the precedence of the logical operators *H *H Revision 3.6 1990/11/20 12:00:00 martin *H added new list package *H *H Revision 3.5 1990/10/04 12:00:00 martin *H extended scanner to allow '1var' and 'rec.1' *H *H Revision 3.4 1990/10/02 12:00:00 martin *H added 'quit' *H *H Revision 3.3 1990/09/30 12:00:00 martin *H changed '-2^2' to '-4' *H *H Revision 3.2 1990/09/24 12:00:00 martin *H fixed 'RdExpr' for '] x->x^2' *H *H Revision 3.1 1990/09/03 12:00:00 martin *H changed identity permutation to '()' *H *H Revision 3.0 1990/08/24 12:00:00 martin *H changed identity permutation to '()' *H ** *N 19-Jun-90 martin ';' should belong to statements, not to sequences */ #include "system.h" /* system dependent functions */ #include "gasman.h" /* dynamic storage manager */ #include "scanner.h" /* reading of single symbols */ #include "idents.h" /* identifier table manager */ #include "integer.h" /* arbitrary size integers */ #include "eval.h" /* 'EVAL', 'HdVoid', 'HdReturn' */ #include "read.h" /* definition part of this module */ /**************************************************************************** ** ** The constructs <Expr> and <Statments> may have themself as subpart, e.g., ** '<Expr>+1' is <Expr> and 'if <Expr> then <Statments> fi;' is <Statments>. ** The functions 'RdExpr' and 'RdStats' must therefor be declared forward. */ TypHandle RdExpr P(( TypSymbolSet follow )); TypHandle RdStats P(( TypSymbolSet follow )); /**************************************************************************** ** *F BinBag( <type>, <hdL>, <hdR> ) . . . . . . . . . . . . make a binary bag ** ** 'BinBag' makes a new bag of the type <type> with the two objects <hdL> ** and <hdR>. No bag is made if an error has occured during the parsing. */ TypHandle BinBag ( type, hdL, hdR ) unsigned int type; TypHandle hdL, hdR; { TypHandle hdBin; if ( NrError >= 1 ) return 0; hdBin = NewBag( type, 2 * SIZE_HD ); PTR(hdBin)[0] = hdL; PTR(hdBin)[1] = hdR; return hdBin; } /**************************************************************************** ** *F RdVar( <follow> ) . . . . . . . . . . . . . . . . . . . . read a variable ** ** 'RdVar' reads a variable and returns the handle to the newly created bag. ** A variable is something that is a legal left hand side in an assignment. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Ident> := a|b|..|z|A|B|..|Z { a|b|..|z|A|B|..|Z|0|..|9|_ } ** ** <Var> := <Ident> ** | <Var> '.' <Ident> ** | <Var> '[' <Expr> ']' ** | <Var> '{' <Expr> '}' ** | <Var> '(' [ <Expr> { ',' <Expr> } ] ')' */ TypHandle HdCurLHS; TypHandle RdVar ( follow ) TypSymbolSet follow; { TypHandle hdVar, hd; TypHandle hdTmp; long level; long i; /* all variables must begin with an identifier */ if ( Symbol == S_IDENT ) hdVar = FindIdent( Value ); else hdVar = 0; Match( S_IDENT, "identifier", follow ); level = 0; /* complain about undefined global variables */ if ( IsUndefinedGlobal && Symbol != S_MAPTO && hdVar != HdCurLHS ) { SyntaxError("warning, undefined global variable"); NrError--; NrErrLine--; } /* followed by one or more selectors */ while ( IS_IN(Symbol,S_LBRACK|S_LBRACE|S_DOT|S_LPAREN) ) { /* <Var> '[' <Expr> ']' list selector */ if ( Symbol == S_LBRACK ) { Match( S_LBRACK, "", 0L ); hd = RdExpr( S_RBRACK|follow ); Match( S_RBRACK, "]", follow ); if ( level == 0 ) { hdVar = BinBag( T_LISTELM, hdVar, hd ); } else { hdTmp = NewBag( T_LISTELML, 2*SIZE_HD+sizeof(long) ); PTR(hdTmp)[0] = hdVar; PTR(hdTmp)[1] = hd; *(long*)(PTR(hdTmp)+2) = level; hdVar = hdTmp; } } /* <VAR> '{' <Expr> '}' sublist selector */ else if ( Symbol == S_LBRACE ) { Match( S_LBRACE, "", 0L ); hd = RdExpr( S_RBRACE|follow ); Match( S_RBRACE, "}", follow ); if ( level == 0 ) { hdVar = BinBag( T_LISTELMS, hdVar, hd ); } else { hdTmp = NewBag( T_LISTELMSL, 2*SIZE_HD+sizeof(long) ); PTR(hdTmp)[0] = hdVar; PTR(hdTmp)[1] = hd; *(long*)(PTR(hdTmp)+2) = level; hdVar = hdTmp; } level += 1; } /* <Var> '.' <Ident> record selector */ else if ( Symbol == S_DOT ) { Match( S_DOT, "", 0L ); if ( Symbol == S_INT ) { hd = FindRecname( Value ); Match( S_INT, "", follow ); } else if ( Symbol == S_IDENT ) { hd = FindRecname( Value ); Match( S_IDENT, "", follow ); } else if ( Symbol == S_LPAREN ) { Match( S_LPAREN, "", follow ); hd = RdExpr( follow ); Match( S_RPAREN, ")", follow ); if ( hd != 0 && TYPE(hd) == T_MAKESTRING ) hd = FindRecname( (char*)PTR(hd) ); } else { SyntaxError("record component name expected"); hd = 0; } hdVar = BinBag( T_RECELM, hdVar, hd ); level = 0; } /* <Var> '(' [ <Expr> { ',' <Expr> } ] ')' function call */ else { Match( S_LPAREN, "", 0L ); hd = NewBag( T_FUNCCALL, 4 * SIZE_HD ); PTR(hd)[0] = hdVar; hdVar = hd; i = 1; if ( Symbol != S_RPAREN ) { i++; if ( SIZE(hdVar) < i * SIZE_HD ) Resize( hdVar, (i+i/8+4) * SIZE_HD ); hd = RdExpr( S_RPAREN|follow ); PTR(hdVar)[i-1] = hd; } while ( Symbol == S_COMMA ) { Match( S_COMMA, "", 0L ); i++; if ( SIZE(hdVar) < i * SIZE_HD ) Resize( hdVar, (i+i/8+4) * SIZE_HD ); hd = RdExpr( S_RPAREN|follow ); PTR(hdVar)[i-1] = hd; } Match( S_RPAREN, ")", follow ); Resize( hdVar, i * SIZE_HD ); level = 0; } } /* return the <Var> bag */ if ( NrError >= 1 ) return 0; return hdVar; } /**************************************************************************** ** *F RdList( <follow> ) . . . . . . . . . . . . . . . . . . . . . read a list ** ** 'RdList' reads a list and returns the handle to the newly created bag. ** Lists have the form '[' <Expr>',' ... ']'. Note that a list may have ** undefined entries, in which case there is no <Expr> between the commas. ** 'RdList' is also responsible for reading ranges, which have the following ** form, '[' <Expr> '..' <Expr> ']'. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <List> := '[' [ <Expr> ] {',' [ <Expr> ] } ']' ** | '[' <Expr> '..' <Expr> ']' */ TypHandle RdList ( follow ) TypSymbolSet follow; { TypHandle hdList; /* handle of the result */ unsigned long len; /* logical length of the list */ TypHandle hd; /* temporary handle */ unsigned long i; /* loop variable */ /* '[' */ Match( S_LBRACK, "", 0L ); hdList = NewBag( T_MAKELIST, 4 * SIZE_HD ); i = 0; len = 0; /* [ <Expr> ] */ if ( Symbol != S_RBRACK ) { i++; if ( SIZE(hdList) <= i * SIZE_HD ) Resize( hdList, (i+i/8+4) * SIZE_HD ); if ( Symbol != S_COMMA ) { hd = RdExpr( S_RBRACK|follow ); PTR(hdList)[i] = hd; len = i; } } /* {',' [ <Expr> ] } */ while ( Symbol == S_COMMA ) { Match( S_COMMA, "", 0L ); i++; if ( SIZE(hdList) <= i*SIZE_HD ) Resize( hdList, (i+i/8+4) * SIZE_HD ); if ( Symbol != S_COMMA && Symbol != S_RBRACK ) { hd = RdExpr( S_RBRACK|follow ); PTR(hdList)[i] = hd; len = i; } } /* '..' <Expr> ']' */ if ( Symbol == S_DOTDOT ) { Match( S_DOTDOT, "", 0L ); i++; if ( 3 < i ) SyntaxError("'..' unexpexcted"); if ( SIZE(hdList) <= i*SIZE_HD ) Resize( hdList, (i+i/8+4) * SIZE_HD ); hd = RdExpr( S_RBRACK|follow ); Match( S_RBRACK, "]", follow ); PTR(hdList)[i] = hd; if ( NrError >= 1 ) return 0; hd = NewBag( T_MAKERANGE, i * SIZE_HD ); PTR(hd)[0] = PTR(hdList)[1]; PTR(hd)[1] = PTR(hdList)[2]; if ( i == 3 ) PTR(hd)[2] = PTR(hdList)[3]; return hd; } /* ']' */ Match( S_RBRACK, "]", follow ); /* return the <List> bag */ Resize( hdList, (i+1)*SIZE_HD ); PTR(hdList)[0] = INT_TO_HD(len); if ( NrError >= 1 ) return 0; return hdList; } /**************************************************************************** ** *F RdRec( <follow> ) . . . . . . . . . . . . . . . . . . . . . read a record ** ** 'RdRec' reads a record, returning a handle to the newly created bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Record> := 'rec( [ <Ident>:=<Expr> {, <Ident>:=<Expr> } ] )' ** ** The bag is resized 16 entries at at time to avoid doing it too often. */ TypHandle RdRec ( follow ) TypSymbolSet follow; { TypHandle hdRec, hd; unsigned long i; /* 'rec(' */ Match( S_IDENT, "", 0L ); Match( S_LPAREN, "(", follow|S_RPAREN|S_COMMA ); hdRec = NewBag( T_MAKEREC, 8 * SIZE_HD ); i = 0; /* [ <Ident> ':=' <Expr> */ if ( Symbol != S_RPAREN ) { i++; if ( SIZE(hdRec) < i*2*SIZE_HD ) Resize( hdRec, (i+i/8+4) * 2 * SIZE_HD ); if ( Symbol == S_INT ) { hd = FindRecname( Value ); Match( S_INT, "", follow ); } else if ( Symbol == S_IDENT ) { hd = FindRecname( Value ); Match( S_IDENT, "", follow ); } else if ( Symbol == S_LPAREN ) { Match( S_LPAREN, "", follow ); hd = RdExpr( follow ); Match( S_RPAREN, ")", follow ); if ( hd != 0 && TYPE(hd) == T_MAKESTRING ) hd = FindRecname( (char*)PTR(hd) ); } else { SyntaxError("record component name expected"); hd = 0; } PTR(hdRec)[2*i-2] = hd; Match( S_ASSIGN, ":=", follow ); hd = RdExpr( S_RPAREN|follow ); PTR(hdRec)[2*i-1] = hd; } /* {',' <Ident> ':=' <Expr> } ] */ while ( Symbol == S_COMMA ) { Match( S_COMMA, "", 0L ); i++; if ( SIZE(hdRec) < i * 2 * SIZE_HD ) Resize( hdRec, (i+i/8+4) * 2 * SIZE_HD ); if ( Symbol == S_INT ) { hd = FindRecname( Value ); Match( S_INT, "", follow ); } else if ( Symbol == S_IDENT ) { hd = FindRecname( Value ); Match( S_IDENT, "", follow ); } else if ( Symbol == S_LPAREN ) { Match( S_LPAREN, "", follow ); hd = RdExpr( follow ); Match( S_RPAREN, ")", follow ); if ( hd != 0 && TYPE(hd) == T_MAKESTRING ) hd = FindRecname( (char*)PTR(hd) ); } else { SyntaxError("record component name expected"); hd = 0; } PTR(hdRec)[2*i-2] = hd; Match( S_ASSIGN, ":=", follow ); hd = RdExpr( S_RPAREN|follow ); PTR(hdRec)[2*i-1] = hd; } /* ')' */ Match( S_RPAREN, ")", follow ); /* return the <Record> bag */ Resize( hdRec, i * 2 * SIZE_HD ); if ( NrError >= 1 ) return 0; return hdRec; } /**************************************************************************** ** *F RdPerm( <hdFirst>, <follow> ) . . . . . . . . . . . . read a permutation ** ** 'RdPerm' reads the rest of a permutation, which starts '( <hdFirst>, ...' ** 'RdPerm' returns the handle of the new created variable permutation bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Permutation> := ( <Expr> {, <Expr>} ) { ( <Expr> {, <Expr>} ) } ** ** If the permutation is constant, i.e., if all <Expr> are simple integers, ** 'RdPerm' converts the 'T_MAKEPERM' to a 'T_PERM' by calling 'EvMakeperm'. ** ** 'RdPerm' is somewhat special, since all other reader functions are called ** with the current Symbol beeing the first of the construct to be read, ** while 'RdPerm' is called with the current Symbol beeing the ',', which is ** the first moment we know that we read a permutation and not an expression ** in parenthesis. This is the reason for the uncommon argument <hdFirst>. ** ** To speed up reading of permutations, the varperm bag is enlarged by 256 ** handles a time and shrunk to the correct size in the end, and the cycles ** bags are initially created with the size of the largest cycle encountered ** so far. It follows that for permutations of prime order no nontrivial ** 'Resize' is ever needed. Cycles are enlarged, if ever 16 handles a time. */ TypHandle RdPerm ( hdFirst, follow ) TypHandle hdFirst; TypSymbolSet follow; { TypHandle hdPerm, hdCyc, hd; unsigned long i, k, m, isConst; isConst = (hdFirst != 0) && (TYPE(hdFirst) == T_INT); hdPerm = NewBag( T_MAKEPERM, 256*SIZE_HD ); i = 1; /* read the rest of the first cycle */ m = 2; hdCyc = NewBag( T_CYCLE, m*SIZE_HD ); k = 1; PTR(hdPerm)[i-1] = hdCyc; PTR(hdCyc)[0] = hdFirst; while ( Symbol == S_COMMA ) { Match( S_COMMA, "", 0L ); if ( ++k*SIZE_HD > SIZE(hdCyc) ) Resize( hdCyc, (k+15)*SIZE_HD ); hd = RdExpr( S_RPAREN|follow ); PTR(hdCyc)[k-1] = hd; isConst = isConst && (hd != 0) && (TYPE(hd) == T_INT); } Match( S_RPAREN, ")", follow ); Resize( hdCyc, k*SIZE_HD ); if ( k > m ) m = k; /* read the other cycles */ while ( Symbol == S_LPAREN ) { Match( S_LPAREN, "", 0L ); if ( ++i*SIZE_HD > SIZE(hdPerm) ) Resize( hdPerm, (i+255)*SIZE_HD ); hdCyc = NewBag( T_CYCLE, m*SIZE_HD ); k = 1; PTR(hdPerm)[i-1] = hdCyc; hd = RdExpr( S_RPAREN|follow ); PTR(hdCyc)[0] = hd; /*if ( Symbol != S_COMMA ) SyntaxError(", expected");*/ while ( Symbol == S_COMMA ) { Match( S_COMMA, "", 0L ); if ( ++k*SIZE_HD > SIZE(hdCyc) ) Resize( hdCyc, (k+15) * SIZE_HD ); hd = RdExpr( S_RPAREN|follow ); PTR(hdCyc)[k-1] = hd; isConst = isConst && (hd != 0) && (TYPE(hd) == T_INT); } Match( S_RPAREN, ")", follow ); Resize( hdCyc, k*SIZE_HD ); if ( k > m ) m = k; } Resize( hdPerm, i*SIZE_HD ); /* return the <Permutation> bag */ if ( NrError >= 1 ) return 0; if ( isConst ) return EVAL( hdPerm ); return hdPerm; } /**************************************************************************** ** *F RdFunc( <follow> ) . . . . . . . . . . . . . read a function definition ** ** 'RdFunc' reads a function definition and returns the handle of the bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Function> := 'function (' [ <Ident> {',' <Ident>} ] ')' ** [ 'local' <Ident> {',' <Ident>} ';' ] ** <Statments> ** 'end' */ TypHandle RdFunc ( follow ) TypSymbolSet follow; { TypHandle hdFun, hd; short nrArg = 0, nrLoc = 0; /* 'function', make the local names know to the symbol tables */ Match( S_FUNCTION, "", 0L ); hdFun = NewBag( T_MAKEFUNC, 2*SIZE_HD + 2*sizeof(short) ); PushFunction( hdFun ); /* '(' [ <Ident> {',' <Ident> } ] ')' */ Match( S_LPAREN, "(", S_IDENT|S_RPAREN|S_LOCAL|STATBEGIN|S_END|follow ); if ( Symbol != S_RPAREN ) { hd = NewBag( T_VAR, SIZE_HD+SyStrlen(Value)+1 ); SyStrncat( (char*)(PTR(hd)+1), Value, SyStrlen(Value) ); Resize( hdFun, SIZE(hdFun) + SIZE_HD ); PTR(hdFun)[++nrArg] = hd; Match( S_IDENT, "ident", S_RPAREN|S_LOCAL|STATBEGIN|S_END|follow ); } while ( Symbol == S_COMMA ) { Match( S_COMMA, "", 0L ); hd = NewBag( T_VAR, SIZE_HD+SyStrlen(Value)+1 ); SyStrncat( (char*)(PTR(hd)+1), Value, SyStrlen(Value) ); Resize( hdFun, SIZE(hdFun) + SIZE_HD ); PTR(hdFun)[++nrArg] = hd; Match( S_IDENT, "ident", S_RPAREN|S_LOCAL|STATBEGIN|S_END|follow ); } Match( S_RPAREN, ")", S_LOCAL|STATBEGIN|S_END|follow ); /* [ 'local' <Ident> {',' <Ident> } ';' ] */ if ( Symbol == S_LOCAL ) { Match( S_LOCAL, "", 0L ); hd = NewBag( T_VAR, SIZE_HD+SyStrlen(Value)+1 ); SyStrncat( (char*)(PTR(hd)+1), Value, SyStrlen(Value) ); Resize( hdFun, SIZE(hdFun) + SIZE_HD ); PTR(hdFun)[ nrArg+ ++nrLoc ] = hd; Match( S_IDENT, "identifier", STATBEGIN|S_END|follow ); while ( Symbol == S_COMMA ) { Match( S_COMMA, "", 0L ); hd = NewBag( T_VAR, SIZE_HD+SyStrlen(Value)+1 ); SyStrncat( (char*)(PTR(hd)+1), Value, SyStrlen(Value) ); Resize( hdFun, SIZE(hdFun) + SIZE_HD ); PTR(hdFun)[ nrArg+ ++nrLoc ] = hd; Match( S_IDENT, "identifier", STATBEGIN|S_END|follow ); } Match( S_SEMICOLON, ";", STATBEGIN|S_END|follow ); } /* function ( arg ) takes a variable number of arguments */ if ( nrArg == 1 && ! SyStrcmp("arg",(char*)(PTR(PTR(hdFun)[nrArg])+1)) ) nrArg = -1; *( (short*)((char*)PTR(hdFun) + SIZE(hdFun)) - 2 ) = nrArg; *( (short*)((char*)PTR(hdFun) + SIZE(hdFun)) - 1 ) = nrLoc; /* <Statments> */ hd = RdStats( S_END|follow ); PTR(hdFun)[0] = hd; Match( S_END, "end", follow ); /* remove the local names from the symbol tables */ PopFunction(); /* return the <Function> bag */ if ( NrError >= 1 ) return 0; return hdFun; } /**************************************************************************** ** *F RdAtom( <follow> ) . . . . . . . . . . . . . . . . . . . . read an atom ** ** 'RdAtom' reads a single atom and returns the handle of the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Atom> := <Int> ** | <Var> ** | '(' <Expr> ')' ** | <Permutation> ** | <Char> ** | <String> ** | <Function> ** | <List> ** | <Record> ** ** <Int> := 0|1|..|9 { 0|1|..|9 } ** ** <Char> := ' <any character> ' ** ** <String> := " { <any character> } " */ TypHandle RdAtom ( follow ) TypSymbolSet follow; { TypHandle hdAt; long i; unsigned long nr, pow; /* <Int> */ /* a little tricky, to avoid calling 'SumInt' and 'ProdInt' too often */ if ( Symbol == S_INT ) { EnterKernel(); nr = 0; pow = 1; hdAt = INT_TO_HD(0); for ( i = 0; Value[i] != '\0'; ++i ) { nr = 10 * nr + Value[i]-'0'; pow = 10 * pow; if ( pow == 100000000L ) { hdAt = SumInt( ProdInt(hdAt,INT_TO_HD(pow)), INT_TO_HD(nr) ); nr = 0; pow = 1; } } if ( hdAt == INT_TO_HD(0) ) hdAt = INT_TO_HD(nr); else if ( pow != 1 ) hdAt = SumInt( ProdInt(hdAt,INT_TO_HD(pow)), INT_TO_HD(nr) ); Match(Symbol,"",0L); ExitKernel( TYPE(hdAt) == T_INT ? 0 : hdAt ); } /* '(' <Expr> ')' */ else if ( Symbol == S_LPAREN ) { Match( S_LPAREN, "", 0L ); if ( Symbol == S_RPAREN ) { Match( S_RPAREN, "", 0L ); hdAt = NewBag( T_PERM16, 0L ); } else { hdAt = RdExpr( follow ); if ( Symbol == S_COMMA ) { hdAt = RdPerm( hdAt, follow ); } else { Match( S_RPAREN, ")", follow ); } } } /* '[' [ <Expr> {, [ <Expr> ] } ] ']' */ else if ( Symbol == S_LBRACK ) { hdAt = RdList( follow ); } /* 'rec(' [ <Ident> ':=' <Expr> {',' <Ident> ':=' <Expr> } ] ')' */ else if ( Symbol == S_IDENT && SyStrcmp( Value, "rec" ) == 0 ) { hdAt = RdRec( follow ); } /* <Char> */ else if ( Symbol == S_CHAR ) { hdAt = NewBag( T_CHAR, 1 ); *((char*)PTR(hdAt)) = Value[0]; Match( S_CHAR, "", 0L ); } /* <String> */ else if ( Symbol == S_STRING ) { hdAt = NewBag( T_MAKESTRING, (unsigned long)(SyStrlen(Value)+1) ); SyStrncat( (char*)(PTR(hdAt)), Value, SyStrlen(Value) ); Match( S_STRING, "", 0L ); } /* <Function> */ else if ( Symbol == S_FUNCTION ) { hdAt = RdFunc( follow ); } /* <Var> */ else if ( Symbol == S_IDENT ) { hdAt = RdVar( follow ); } /* generate an error, we want to see an expression */ else { Match( S_INT, "expression", follow ); hdAt = 0; } /* return the <Atom> bag */ if ( NrError >= 1 ) return 0; return hdAt; } /**************************************************************************** ** *F RdFactor( <follow> ) . . . . . . . . . . . . . . . . . . . read a factor ** ** 'RdFactor' reads a factor and returns the handle to the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Factor> := {'+'|'-'} <Atom> [ '^' {'+'|'-'} <Atom> ] */ TypHandle RdFactor ( follow ) TypSymbolSet follow; { TypHandle hdFac, hdAt; long sign1, sign2; /* { '+'|'-' } leading sign */ sign1 = 0; while ( Symbol == S_MINUS || Symbol == S_PLUS ) { if ( sign1 == 0 ) sign1 = 1; if ( Symbol == S_MINUS ) sign1 = - sign1; Match( Symbol, "", 0L ); } /* <Atom> */ hdFac = RdAtom( follow ); /* ['^' <Atom> ] implemented as {'^' <Atom> } for better error message */ while ( Symbol == S_POW ) { /* match the '^' away */ Match( S_POW, "", 0L ); /* { '+'|'-' } leading sign */ sign2 = 0; while ( Symbol == S_MINUS || Symbol == S_PLUS ) { if ( sign2 == 0 ) sign2 = 1; if ( Symbol == S_MINUS ) sign2 = - sign2; Match( Symbol, "", 0L ); } /* ['^' <Atom>] */ hdAt = RdAtom(follow); /* add the unary minus bag */ if ( sign2 == -1 && NrError == 0 && TYPE(hdFac) <= T_INTNEG ) hdAt = ProdInt( INT_TO_HD(-1), hdAt ); else if ( sign2 == -1 && NrError == 0 ) hdAt = BinBag( T_PROD, INT_TO_HD(-1), hdAt ); /* create the power bag */ hdFac = BinBag( T_POW, hdFac, hdAt ); if ( Symbol == S_POW ) SyntaxError("'^' is not associative"); } /* add the unary minus bag */ if ( sign1 == -1 && NrError == 0 && TYPE(hdFac) <= T_INTNEG ) hdFac = ProdInt( INT_TO_HD(-1), hdFac ); else if ( sign1 == -1 && NrError == 0 ) hdFac = BinBag( T_PROD, INT_TO_HD(-1), hdFac ); /* return the <Factor> bag */ return hdFac; } /**************************************************************************** ** *F RdTerm( <follow> ) . . . . . . . . . . . . . . . . . . . . . read a term ** ** 'RdTerm' reads a term and returns the handle of the new expression bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Term> := <Factor> { '*'|'/'|'mod' <Factor> } */ TypHandle RdTerm ( follow ) TypSymbolSet follow; { TypHandle hdTer, hdFac; unsigned int type; /* <Factor> */ hdTer = RdFactor( follow ); /* { '*'|'/'|'mod' <Factor> } */ /* do not use 'IS_IN', since 'IS_IN(S_POW,S_MULT|S_DIV|S_MOD)' is true */ while ( Symbol==S_MULT || Symbol==S_DIV || Symbol==S_MOD ) { switch ( Symbol ) { case S_MULT: type = T_PROD; break; case S_DIV: type = T_QUO; break; default: type = T_MOD; break; } Match( Symbol, "", 0L ); hdFac = RdFactor( follow ); hdTer = BinBag( type, hdTer, hdFac ); } /* return the <Term> bag */ return hdTer; } /**************************************************************************** ** *F RdAri( <follow> ) . . . . . . . . . . . . . read an arithmetic expression ** ** Reads an arithmetic expression, returning a handle to the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Arith> := <Term> { '+'|'-' <Term> } */ TypHandle RdAri ( follow ) TypSymbolSet follow; { TypHandle hdAri, hdTer; unsigned int type; /* <Term> */ hdAri = RdTerm( follow ); /* { '+'|'-' <Term> } */ while ( IS_IN(Symbol,S_PLUS|S_MINUS) ) { type = (Symbol == S_PLUS) ? T_SUM : T_DIFF; Match( Symbol, "", 0L ); hdTer = RdTerm( follow ); hdAri = BinBag( type, hdAri, hdTer ); } /* return the <Arith> bag */ return hdAri; } /**************************************************************************** ** *F RdRel( <follow> ) . . . . . . . . . . . . .. read a relational expression ** ** 'RdRel' reads a relational expression, returning a handle to the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Rel> := { 'not' } <Arith> { '=|<>|<|>|<=|>=|in' <Arith> } */ TypHandle RdRel ( follow ) TypSymbolSet follow; { TypHandle hdRel, hdAri; unsigned int type; short isNot; /* { 'not' } */ isNot = 0; while ( Symbol == S_NOT ) { isNot = ! isNot; Match( S_NOT, "", 0L ); } /* <Arith> */ hdRel = RdAri( follow ); /* { '=|<>|<|>|<=|>=|in' <Arith> } */ if ( IS_IN(Symbol,S_EQ|S_LT|S_GT|S_NE|S_LE|S_GE|S_IN) ) { switch ( Symbol ) { case S_EQ: type = T_EQ; break; case S_LT: type = T_LT; break; case S_GT: type = T_GT; break; case S_NE: type = T_NE; break; case S_LE: type = T_LE; break; case S_GE: type = T_GE; break; default: type = T_IN; break; } Match( Symbol, "", 0L ); hdAri = RdAri( follow ); hdRel = BinBag( type, hdRel, hdAri ); } /* return the <Rel> bag */ if ( isNot && NrError == 0 ) { hdAri = NewBag( T_NOT, SIZE_HD ); PTR(hdAri)[0] = hdRel; hdRel = hdAri; } return hdRel; } /**************************************************************************** ** *F RdAnd( <follow> ) . . . . . . . . . . . . . read a logical and expression ** ** 'RdAnd' reads a logical expression and returns the handle of the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <And> := <Rel> { 'and' <Rel> } */ TypHandle RdAnd ( follow ) TypSymbolSet follow; { TypHandle hdAnd, hdRel; /* <Rel> */ hdAnd = RdRel( follow ); /* { 'and' <Rel> } */ while ( Symbol == S_AND ) { Match( Symbol, "", 0L ); hdRel = RdRel( follow ); hdAnd = BinBag( T_AND, hdAnd, hdRel ); } /* return the <And> bag */ return hdAnd; } /**************************************************************************** ** *F RdLog( <follow> ) . . . . . . . . . . . . . . . read a logical expression ** ** 'RdLog' reads a logical expression and returns the handle of the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Log> := <And> { 'or' <And> } */ TypHandle RdLog ( follow ) TypSymbolSet follow; { TypHandle hdLog, hdAnd; /* <And> */ hdLog = RdAnd( follow ); /* { 'or' <And> } */ while ( Symbol == S_OR ) { Match( Symbol, "", 0L ); hdAnd = RdAnd( follow ); hdLog = BinBag( T_OR, hdLog, hdAnd ); } /* return the <Log> bag */ return hdLog; } /**************************************************************************** ** *F RdExpr( <follow> ) . . . . . . . . . . . . . . . . . read an expression ** ** 'RdExpr' an expression, returning a handle to the newly created bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Expr> := <Log> ** | <Var> [ '->' <Log> ] */ TypHandle RdExpr ( follow ) TypSymbolSet follow; { TypHandle hdExp, hdFun, hdTmp; /* <Var> */ hdExp = RdLog( follow|S_MAPTO ); /* [ '->' <Expr> ] */ if ( Symbol == S_MAPTO ) { if ( hdExp != 0 && TYPE(hdExp) != T_VAR ) SyntaxError("left hand side of '->' must be a variable"); /* make a copy of the variable returned by 'RdLog' */ if ( NrError == 0 ) { hdTmp = NewBag( T_VAR, SIZE(hdExp) ); SyStrncat( (char*)(PTR(hdTmp)+1), (char*)(PTR(hdExp)+1), SyStrlen( (char*)(PTR(hdExp)+1) ) ); } else { hdTmp = NewBag( T_VAR, SIZE_HD + 1 ); } /* make a function bag and push it on the function stack */ hdFun = NewBag( T_MAKEFUNC, 3*SIZE_HD + 2*sizeof(short) ); PTR(hdFun)[1] = hdTmp; *( (short*)((char*)PTR(hdFun) + SIZE(hdFun)) - 2 ) = 1; *( (short*)((char*)PTR(hdFun) + SIZE(hdFun)) - 1 ) = 0; PushFunction( hdFun ); /* match away the '->' */ Match( Symbol, "", 0L ); /* read the expression */ hdExp = RdLog( follow ); hdTmp = NewBag( T_RETURN, SIZE_HD ); PTR(hdTmp)[0] = hdExp; PTR(hdFun)[0] = hdTmp; /* the function is the expression */ hdExp = hdFun; PopFunction(); } /* return the <Expr> bag */ return hdExp; } /**************************************************************************** ** *F RdIf( <follow> ) . . . . . . . . . . . . . . . . . read an if statement ** ** 'RdIf' reads an 'if'-statement, returning a handle to the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Statement> := 'if' <Expr> 'then' <Statments> ** { 'elif' <Expr> 'then' <Statments> } ** [ 'else' <Statments> ] ** 'fi' */ TypHandle RdIf ( follow ) TypSymbolSet follow; { TypHandle hd[128], hdIf; short i = 0; /* 'if' <Expr> 'then' <Statments> */ Match( S_IF, "", 0L ); hd[i++] = RdExpr( S_THEN|S_ELIF|S_ELSE|S_FI|follow ); Match( S_THEN, "then", STATBEGIN|S_ELIF|S_ELSE|S_FI|follow ); hd[i++] = RdStats( S_ELIF|S_ELSE|S_FI|follow ); /* { 'elif' <Expr> 'then' <Statments> } */ while ( Symbol == S_ELIF ) { Match( S_ELIF, "", 0L ); hd[i++] = RdExpr( S_THEN|S_ELIF|S_ELSE|S_FI|follow ); Match( S_THEN, "then", STATBEGIN|S_ELIF|S_ELSE|S_FI|follow ); hd[i++] = RdStats( S_ELIF|S_ELSE|S_FI|follow ); } /* [ 'else' <Statments> ] */ if ( Symbol == S_ELSE ) { Match( S_ELSE, "", 0L ); hd[i++] = RdStats( S_FI|follow ); } /* 'fi' */ Match( S_FI, "fi", follow ); /* create and return the 'if'-statement bag */ if ( NrError >= 1 ) return 0; hdIf = NewBag( T_IF, i * SIZE_HD ); while ( i >= 1 ) { --i; PTR(hdIf)[i] = hd[i]; } return hdIf; } /**************************************************************************** ** *F RdFor( <follow> ) . . . . . . . . . . . . . . . . . read a for statement ** ** 'RdFor' reads a 'for'-loop, returning a handle to the newly created bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Statement> := 'for' <Var> 'in' <Expr> 'do' ** <Statments> ** 'od' */ TypHandle RdFor ( follow ) TypSymbolSet follow; { TypHandle hdVar, hdList, hdStats, hdFor; /* 'for' <Var> */ Match( S_FOR, "", 0L ); hdVar = FindIdent( Value ); Match( S_IDENT, "identifier", S_IN|S_DO|S_OD|follow ); /* complain about undefined global variables */ if ( IsUndefinedGlobal ) { SyntaxError("warning, undefined global variable"); NrError--; NrErrLine--; } /* 'in' <Expr> */ Match( S_IN, "in", S_DO|S_OD|follow ); hdList = RdExpr( S_DO|S_OD|follow ); /* 'do' <Statments> */ Match( S_DO, "do", STATBEGIN|S_OD|follow ); hdStats = RdStats( S_OD|follow ); /* 'od' */ Match( S_OD, "od", follow ); /* create and return the 'for'-loop bag */ if ( NrError >= 1 ) return 0; hdFor = NewBag( T_FOR, 3 * SIZE_HD ); PTR(hdFor)[0] = hdVar; PTR(hdFor)[1] = hdList; PTR(hdFor)[2] = hdStats; return hdFor; } /**************************************************************************** ** *F RdWhile( <follow> ) . . . . . . . . . . . . . . . read a while statement ** ** 'RdWhile' reads a 'while'-loop, returning a handle to the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Statement> := 'while' <Expr> 'do' ** <Statments> ** 'od' */ TypHandle RdWhile ( follow ) TypSymbolSet follow; { TypHandle hdCond, hdStats, hdWhile; /* 'while' <Expr> 'do' */ Match( S_WHILE, "", 0L ); hdCond = RdExpr( S_DO|S_OD|follow ); Match( S_DO, "do", STATBEGIN|S_DO|follow ); /* <Statments> */ hdStats = RdStats( S_OD|follow ); /* 'od' */ Match( S_OD, "od", follow ); /* create and return the 'while'-loop bag */ if ( NrError >= 1 ) return 0; hdWhile = NewBag( T_WHILE, 2 * SIZE_HD ); PTR(hdWhile)[0] = hdCond; PTR(hdWhile)[1] = hdStats; return hdWhile; } /**************************************************************************** ** *F RdRepeat( <follow> ) . . . . . . . . . . . . . . read a repeat statement ** ** 'RdRepeat' reads a 'repeat'-loop, returning a handle to the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Statement> := 'repeat' ** <Statments> ** 'until' <Expr> */ TypHandle RdRepeat ( follow ) TypSymbolSet follow; { TypHandle hdStats, hdCond, hdRep; /* 'repeat' <Statments> */ Match( S_REPEAT, "", 0L ); hdStats = RdStats( S_UNTIL|follow ); /* 'until' <Expr> */ Match( S_UNTIL, "until", EXPRBEGIN|follow ); hdCond = RdExpr( follow ); /* create and return the 'repeat'-loop bag */ if ( NrError >= 1 ) return 0; hdRep = NewBag( T_REPEAT, 2 * SIZE_HD ); PTR(hdRep)[0] = hdCond; PTR(hdRep)[1] = hdStats; return hdRep; } /**************************************************************************** ** *F RdReturn( <follow> ) . . . . . . . . . . . . . . read a return statement ** ** 'RdReturn' reads a 'return'-statement, returning a handle of the new bag. ** Return with no expression following is used in functions to return void. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Statement> := 'return' [ <Expr> ] ** ** It is still legal to use parenthesis but they are no longer required, ** a return statememt is not a function call and should not look like one. */ TypHandle RdReturn ( follow ) TypSymbolSet follow; { TypHandle hdRet, hdExpr; /* skip the return symbol */ Match( S_RETURN, "", 0L ); /* 'return' with no expression following */ if ( Symbol == S_SEMICOLON ) { if ( NrError >= 1 ) return 0; hdRet = NewBag( T_RETURN, SIZE_HD ); PTR(hdRet)[0] = HdVoid; } /* 'return' with an expression following */ else { hdExpr = RdExpr( follow ); if ( NrError >= 1 ) return 0; hdRet = NewBag( T_RETURN, SIZE_HD ); PTR(hdRet)[0] = hdExpr; } /* return the 'return'-statement bag */ return hdRet; } /**************************************************************************** ** *F RdQuit( <follow> ) . . . . . . . . . . . . . . . . read a quit statement ** ** 'RdQuit' reads a 'quit' statement, returning a handle of the new bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Statement> := 'quit' */ TypHandle RdQuit ( follow ) TypSymbolSet follow; { TypHandle hdQuit; Match( S_QUIT, "", follow ); hdQuit = NewBag( T_RETURN, SIZE_HD ); PTR(hdQuit)[0] = HdReturn; return hdQuit; } /**************************************************************************** ** *F RdStat( <follow> ) . . . . . . . . . . . . . . . . . . read a statement ** ** Reads a single statement, returning the handle to the newly created bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Statment> := <Expr> ** | <Var> ':=' <Expr> ** | 'if' <Expr> 'then' <Statments> ** { 'elif' <Expr> 'then' <Statments> } ** [ 'else' <Statments> ] 'fi' ** | 'for' <Var> 'in' <Expr> 'do' <Statments> 'od' ** | 'while' <Expr> 'do' <Statments> 'od' ** | 'repeat' <Statments> 'until' <Expr> ** | 'return' [ <Expr> ] ** | 'quit' */ TypHandle RdStat ( follow ) TypSymbolSet follow; { TypHandle hd, hdExpr, hdAss; /* handle those cases where the statement has a unique prefix symbol */ if ( Symbol == S_IF ) return RdIf( follow ); if ( Symbol == S_FOR ) return RdFor( follow ); if ( Symbol == S_WHILE ) return RdWhile( follow ); if ( Symbol == S_REPEAT ) return RdRepeat( follow ); if ( Symbol == S_RETURN ) return RdReturn( follow ); if ( Symbol == S_QUIT ) return RdQuit( follow ); /* read an expression */ hd = RdExpr( S_ASSIGN|follow ); if ( Symbol != S_ASSIGN ) return hd; /* if the expression is followed by := it is an assignment */ if ( hd != 0 && TYPE(hd) != T_VAR && TYPE(hd) != T_VARAUTO && TYPE(hd) != T_LISTELM && TYPE(hd) != T_LISTELML && TYPE(hd) != T_LISTELMS && TYPE(hd) != T_LISTELMSL && TYPE(hd) != T_RECELM ) SyntaxError("left hand side of assignment must be a variable"); Match( S_ASSIGN, "", 0L ); if ( HdCurLHS == 0 ) { HdCurLHS = hd; hdExpr = RdExpr( follow ); HdCurLHS = 0; } else { hdExpr = RdExpr( follow ); } /* create an assignment bag and return it */ if ( NrError >= 1 ) return 0; if ( TYPE(hd)==T_VAR ) hdAss = BinBag(T_VARASS, hd,hdExpr); else if ( TYPE(hd)==T_VARAUTO ) hdAss = BinBag(T_VARASS, hd,hdExpr); else if ( TYPE(hd)==T_LISTELM ) hdAss = BinBag(T_LISTASS, hd,hdExpr); else if ( TYPE(hd)==T_LISTELML ) hdAss = BinBag(T_LISTASSL, hd,hdExpr); else if ( TYPE(hd)==T_LISTELMS ) hdAss = BinBag(T_LISTASSS, hd,hdExpr); else if ( TYPE(hd)==T_LISTELMSL ) hdAss = BinBag(T_LISTASSSL,hd,hdExpr); else hdAss = BinBag(T_RECASS, hd,hdExpr); return hdAss; } /**************************************************************************** ** *F RdStats( <follow> ) . . . . . . . . . . . . . . read a statement sequence ** ** Reads a statement sequence, returning a handle to the newly created bag. ** In case of an error it skips all symbols up to one contained in <follow>. ** ** <Statments> := { <Statment> ; } ** | ; ** ** A single semicolon is an empty statement sequence not an empty statement. */ TypHandle RdStats ( follow ) TypSymbolSet follow; { TypHandle hdStats, hd [1024]; short i = 0; /* a single semicolon is an empty statement sequence */ if ( Symbol == S_SEMICOLON ) { Match( S_SEMICOLON, "", 0L ); } /* { <Statement> ; } */ else { while ( IS_IN(Symbol,STATBEGIN) || i == 0 ) { if ( i == 1024 ) { SyntaxError("sorry, can not read more than 1024 statements"); i = 0; } hd[i++] = RdStat( S_SEMICOLON|follow ); if ( Symbol == S_SEMICOLON && hd[i-1] != 0 && TYPE(hd[i-1]) != T_VARASS && TYPE(hd[i-1]) != T_LISTASS && TYPE(hd[i-1]) != T_LISTASSL && TYPE(hd[i-1]) != T_LISTASSS && TYPE(hd[i-1]) != T_LISTASSSL && TYPE(hd[i-1]) != T_RECASS && !(T_FUNCCALL<=TYPE(hd[i-1]) && TYPE(hd[i-1])<=T_RETURN)) { SyntaxError("warning, this statement has no effect"); NrError--; NrErrLine--; } Match( S_SEMICOLON, ";", follow ); } } /* create and return the statement sequence bag */ if ( NrError >= 1 ) return 0; if ( i == 1 ) return hd[0]; hdStats = NewBag( T_STATSEQ, i * SIZE_HD ); while ( i >= 1 ) { --i; PTR(hdStats)[i] = hd[i]; } return hdStats; } /**************************************************************************** ** *F ReadIt() . . . . . . . . . . . . . . . . . read a statement interactivly ** ** 'ReadIt' reads a single statement, returning the handle to the new bag. ** This is the only reading function that doesn't expect the first symbol of ** its input already read and wont read the first symbol of the next input. ** This is the main interface function for the various ReadEvalPrintLoops. ** ** It has this funny name, because 'Read' would give name clash with 'read' ** from the C library on the stupid VAX, which turns all names to uppercase. */ TypHandle ReadIt () { TypHandle hd; /* get the first symbol from the input */ Match( Symbol, "", 0L ); /* print only a partial prompt from now on */ Prompt = "> "; if ( Symbol == S_SEMICOLON || Symbol == S_EOF ) return 0; /* read a statement */ hd = RdStat( S_SEMICOLON|S_EOF ); /* every statement must be terminated by a semicolon */ if ( Symbol != S_SEMICOLON ) SyntaxError("; expected"); if ( Symbol == S_EOF ) return 0; if ( NrError >= 1 ) return 0; return hd; } /**************************************************************************** ** *E Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables ** ** Local Variables: ** mode: outline ** outline-regexp: "*A\\|*F\\|*V\\|*T\\|*E" ** fill-column: 73 ** fill-prefix: "** " ** eval: (local-set-key "\t" 'c-indent-command) ** eval: (local-set-key ";" 'electric-c-semi ) ** eval: (local-set-key "{" 'electric-c-brace) ** eval: (local-set-key "}" 'electric-c-brace) ** eval: (hide-body) ** End: */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.