2000-05-29 14:26:00 +00:00
/*
* * This file contains all sources ( including headers ) to the LEMON
* * LALR ( 1 ) parser generator . The sources have been combined into a
2001-04-03 16:53:21 +00:00
* * single file to make it easy to include LEMON in the source tree
* * and Makefile of another program .
2000-05-29 14:26:00 +00:00
* *
2001-09-16 00:13:26 +00:00
* * The author of this program disclaims copyright .
2000-05-29 14:26:00 +00:00
*/
# include <stdio.h>
2003-04-15 01:49:48 +00:00
# include <stdarg.h>
2000-05-29 14:26:00 +00:00
# include <string.h>
# include <ctype.h>
2003-10-21 13:16:03 +00:00
# include <stdlib.h>
2007-07-18 18:16:29 +00:00
# include <assert.h>
2000-05-29 14:26:00 +00:00
2015-10-29 13:48:15 +00:00
# define ISSPACE(X) isspace((unsigned char)(X))
# define ISDIGIT(X) isdigit((unsigned char)(X))
# define ISALNUM(X) isalnum((unsigned char)(X))
# define ISALPHA(X) isalpha((unsigned char)(X))
# define ISUPPER(X) isupper((unsigned char)(X))
# define ISLOWER(X) islower((unsigned char)(X))
2000-05-29 14:26:00 +00:00
# ifndef __WIN32__
# if defined(_WIN32) || defined(WIN32)
2012-08-20 15:53:54 +00:00
# define __WIN32__
2000-05-29 14:26:00 +00:00
# endif
# endif
2007-07-30 18:31:53 +00:00
# ifdef __WIN32__
2010-11-23 20:55:27 +00:00
# ifdef __cplusplus
extern " C " {
# endif
extern int access ( const char * path , int mode ) ;
# ifdef __cplusplus
}
# endif
2007-07-30 18:31:53 +00:00
# else
# include <unistd.h>
# endif
2000-05-29 14:26:00 +00:00
/* #define PRIVATE static */
# define PRIVATE
# ifdef TEST
# define MAXRHS 5 /* Set low to exercise exception code */
# else
# define MAXRHS 1000
# endif
2019-06-03 15:09:25 +00:00
extern void memory_error ( ) ;
2010-07-18 11:35:53 +00:00
static int showPrecedenceConflict = 0 ;
2007-07-18 18:16:29 +00:00
static char * msort ( char * , char * * , int ( * ) ( const char * , const char * ) ) ;
2000-05-29 14:26:00 +00:00
2008-08-13 20:09:06 +00:00
/*
* * Compilers are getting increasingly pedantic about type conversions
* * as C evolves ever closer to Ada . . . . To work around the latest problems
* * we have to define the following variant of strlen ( ) .
*/
# define lemonStrlen(X) ((int)strlen(X))
2014-01-10 23:21:00 +00:00
/*
* * Compilers are starting to complain about the use of sprintf ( ) and strcpy ( ) ,
* * saying they are unsafe . So we define our own versions of those routines too .
* *
* * There are three routines here : lemon_sprintf ( ) , lemon_vsprintf ( ) , and
2015-09-04 18:03:45 +00:00
* * lemon_addtext ( ) . The first two are replacements for sprintf ( ) and vsprintf ( ) .
2014-01-10 23:21:00 +00:00
* * The third is a helper routine for vsnprintf ( ) that adds texts to the end of a
* * buffer , making sure the buffer is always zero - terminated .
* *
* * The string formatter is a minimal subset of stdlib sprintf ( ) supporting only
* * a few simply conversions :
* *
* * % d
* * % s
* * % . * s
* *
*/
static void lemon_addtext (
char * zBuf , /* The buffer to which text is added */
int * pnUsed , /* Slots of the buffer used so far */
const char * zIn , /* Text to add */
2014-01-11 03:06:18 +00:00
int nIn , /* Bytes of text to add. -1 to use strlen() */
int iWidth /* Field width. Negative to left justify */
2014-01-10 23:21:00 +00:00
) {
if ( nIn < 0 ) for ( nIn = 0 ; zIn [ nIn ] ; nIn + + ) { }
2014-01-11 03:27:37 +00:00
while ( iWidth > nIn ) { zBuf [ ( * pnUsed ) + + ] = ' ' ; iWidth - - ; }
2014-01-10 23:21:00 +00:00
if ( nIn = = 0 ) return ;
memcpy ( & zBuf [ * pnUsed ] , zIn , nIn ) ;
* pnUsed + = nIn ;
2014-01-11 03:27:37 +00:00
while ( ( - iWidth ) > nIn ) { zBuf [ ( * pnUsed ) + + ] = ' ' ; iWidth + + ; }
2014-01-10 23:21:00 +00:00
zBuf [ * pnUsed ] = 0 ;
}
static int lemon_vsprintf ( char * str , const char * zFormat , va_list ap ) {
2014-01-14 10:17:21 +00:00
int i , j , k , c ;
2014-01-10 23:21:00 +00:00
int nUsed = 0 ;
const char * z ;
char zTemp [ 50 ] ;
str [ 0 ] = 0 ;
for ( i = j = 0 ; ( c = zFormat [ i ] ) ! = 0 ; i + + ) {
if ( c = = ' % ' ) {
2014-01-11 03:06:18 +00:00
int iWidth = 0 ;
lemon_addtext ( str , & nUsed , & zFormat [ j ] , i - j , 0 ) ;
2014-01-10 23:21:00 +00:00
c = zFormat [ + + i ] ;
2015-10-29 13:48:15 +00:00
if ( ISDIGIT ( c ) | | ( c = = ' - ' & & ISDIGIT ( zFormat [ i + 1 ] ) ) ) {
2014-01-11 03:06:18 +00:00
if ( c = = ' - ' ) i + + ;
2015-10-29 13:48:15 +00:00
while ( ISDIGIT ( zFormat [ i ] ) ) iWidth = iWidth * 10 + zFormat [ i + + ] - ' 0 ' ;
2014-01-11 03:06:18 +00:00
if ( c = = ' - ' ) iWidth = - iWidth ;
c = zFormat [ i ] ;
}
2014-01-10 23:21:00 +00:00
if ( c = = ' d ' ) {
int v = va_arg ( ap , int ) ;
if ( v < 0 ) {
2014-01-11 03:06:18 +00:00
lemon_addtext ( str , & nUsed , " - " , 1 , iWidth ) ;
2014-01-10 23:21:00 +00:00
v = - v ;
} else if ( v = = 0 ) {
2014-01-11 03:06:18 +00:00
lemon_addtext ( str , & nUsed , " 0 " , 1 , iWidth ) ;
2014-01-10 23:21:00 +00:00
}
k = 0 ;
while ( v > 0 ) {
k + + ;
zTemp [ sizeof ( zTemp ) - k ] = ( v % 10 ) + ' 0 ' ;
v / = 10 ;
}
2014-01-11 03:06:18 +00:00
lemon_addtext ( str , & nUsed , & zTemp [ sizeof ( zTemp ) - k ] , k , iWidth ) ;
2014-01-10 23:21:00 +00:00
} else if ( c = = ' s ' ) {
z = va_arg ( ap , const char * ) ;
2014-01-11 03:06:18 +00:00
lemon_addtext ( str , & nUsed , z , - 1 , iWidth ) ;
2014-01-10 23:21:00 +00:00
} else if ( c = = ' . ' & & memcmp ( & zFormat [ i ] , " .*s " , 3 ) = = 0 ) {
i + = 2 ;
k = va_arg ( ap , int ) ;
z = va_arg ( ap , const char * ) ;
2014-01-11 03:06:18 +00:00
lemon_addtext ( str , & nUsed , z , k , iWidth ) ;
2014-01-10 23:21:00 +00:00
} else if ( c = = ' % ' ) {
2014-01-11 03:06:18 +00:00
lemon_addtext ( str , & nUsed , " % " , 1 , 0 ) ;
2014-01-10 23:21:00 +00:00
} else {
fprintf ( stderr , " illegal format \n " ) ;
exit ( 1 ) ;
}
j = i + 1 ;
}
}
2014-01-11 03:06:18 +00:00
lemon_addtext ( str , & nUsed , & zFormat [ j ] , i - j , 0 ) ;
2014-01-10 23:21:00 +00:00
return nUsed ;
}
static int lemon_sprintf ( char * str , const char * format , . . . ) {
va_list ap ;
int rc ;
va_start ( ap , format ) ;
rc = lemon_vsprintf ( str , format , ap ) ;
va_end ( ap ) ;
return rc ;
}
static void lemon_strcpy ( char * dest , const char * src ) {
while ( ( * ( dest + + ) = * ( src + + ) ) ! = 0 ) { }
}
static void lemon_strcat ( char * dest , const char * src ) {
while ( * dest ) dest + + ;
lemon_strcpy ( dest , src ) ;
}
2010-02-14 17:14:22 +00:00
/* a few forward declarations... */
struct rule ;
struct lemon ;
struct action ;
2007-07-18 18:16:29 +00:00
static struct action * Action_new ( void ) ;
static struct action * Action_sort ( struct action * ) ;
2000-05-29 14:26:00 +00:00
/********** From the file "build.h" ************************************/
2017-04-14 19:44:15 +00:00
void FindRulePrecedences ( struct lemon * ) ;
void FindFirstSets ( struct lemon * ) ;
void FindStates ( struct lemon * ) ;
void FindLinks ( struct lemon * ) ;
void FindFollowSets ( struct lemon * ) ;
void FindActions ( struct lemon * ) ;
2000-05-29 14:26:00 +00:00
/********* From the file "configlist.h" *********************************/
2010-02-14 17:14:22 +00:00
void Configlist_init ( void ) ;
struct config * Configlist_add ( struct rule * , int ) ;
struct config * Configlist_addbasis ( struct rule * , int ) ;
void Configlist_closure ( struct lemon * ) ;
void Configlist_sort ( void ) ;
void Configlist_sortbasis ( void ) ;
struct config * Configlist_return ( void ) ;
struct config * Configlist_basis ( void ) ;
void Configlist_eat ( struct config * ) ;
void Configlist_reset ( void ) ;
2000-05-29 14:26:00 +00:00
/********* From the file "error.h" ***************************************/
2003-04-15 01:49:48 +00:00
void ErrorMsg ( const char * , int , const char * , . . . ) ;
2000-05-29 14:26:00 +00:00
/****** From the file "option.h" ******************************************/
2010-02-14 17:14:22 +00:00
enum option_type { OPT_FLAG = 1 , OPT_INT , OPT_DBL , OPT_STR ,
OPT_FFLAG , OPT_FINT , OPT_FDBL , OPT_FSTR } ;
2000-05-29 14:26:00 +00:00
struct s_options {
2010-02-14 17:14:22 +00:00
enum option_type type ;
const char * label ;
2000-05-29 14:26:00 +00:00
char * arg ;
2010-02-14 17:14:22 +00:00
const char * message ;
2000-05-29 14:26:00 +00:00
} ;
2010-02-14 17:14:22 +00:00
int OptInit ( char * * , struct s_options * , FILE * ) ;
int OptNArgs ( void ) ;
char * OptArg ( int ) ;
void OptErr ( int ) ;
void OptPrint ( void ) ;
2000-05-29 14:26:00 +00:00
/******** From the file "parse.h" *****************************************/
2010-02-14 17:14:22 +00:00
void Parse ( struct lemon * lemp ) ;
2000-05-29 14:26:00 +00:00
/********* From the file "plink.h" ***************************************/
2010-02-14 17:14:22 +00:00
struct plink * Plink_new ( void ) ;
void Plink_add ( struct plink * * , struct config * ) ;
void Plink_copy ( struct plink * * , struct plink * ) ;
void Plink_delete ( struct plink * ) ;
2000-05-29 14:26:00 +00:00
/********** From the file "report.h" *************************************/
2010-02-14 17:14:22 +00:00
void Reprint ( struct lemon * ) ;
void ReportOutput ( struct lemon * ) ;
2019-11-26 02:22:39 +00:00
void ReportTable ( struct lemon * , int , int ) ;
2010-02-14 17:14:22 +00:00
void ReportHeader ( struct lemon * ) ;
void CompressTables ( struct lemon * ) ;
void ResortStates ( struct lemon * ) ;
2000-05-29 14:26:00 +00:00
/********** From the file "set.h" ****************************************/
2010-02-14 17:14:22 +00:00
void SetSize ( int ) ; /* All sets will be of size N */
char * SetNew ( void ) ; /* A new set for element 0..N */
void SetFree ( char * ) ; /* Deallocate a set */
int SetAdd ( char * , int ) ; /* Add element to a set */
int SetUnion ( char * , char * ) ; /* A <- A U B, thru element N */
2000-05-29 14:26:00 +00:00
# define SetFind(X,Y) (X[Y]) /* True if Y is in set X */
/********** From the file "struct.h" *************************************/
/*
* * Principal data structures for the LEMON parser generator .
*/
2007-08-23 02:50:56 +00:00
typedef enum { LEMON_FALSE = 0 , LEMON_TRUE } Boolean ;
2000-05-29 14:26:00 +00:00
/* Symbols (terminals and nonterminals) of the grammar are stored
* * in the following : */
2010-02-14 17:14:22 +00:00
enum symbol_type {
TERMINAL ,
NONTERMINAL ,
MULTITERMINAL
} ;
enum e_assoc {
LEFT ,
RIGHT ,
NONE ,
UNK
} ;
2000-05-29 14:26:00 +00:00
struct symbol {
2010-02-14 17:14:22 +00:00
const char * name ; /* Name of the symbol */
2000-05-29 14:26:00 +00:00
int index ; /* Index number for this symbol */
2010-02-14 17:14:22 +00:00
enum symbol_type type ; /* Symbols are all either TERMINALS or NTs */
2000-05-29 14:26:00 +00:00
struct rule * rule ; /* Linked list of rules of this (if an NT) */
2002-06-06 18:54:39 +00:00
struct symbol * fallback ; /* fallback token in case this token doesn't parse */
2000-05-29 14:26:00 +00:00
int prec ; /* Precedence if defined (-1 otherwise) */
2010-02-14 17:14:22 +00:00
enum e_assoc assoc ; /* Associativity if precedence is defined */
2000-05-29 14:26:00 +00:00
char * firstset ; /* First-set for all rules of this symbol */
Boolean lambda ; /* True if NT and can generate an empty string */
2008-01-22 01:48:05 +00:00
int useCnt ; /* Number of times used */
2000-05-29 14:26:00 +00:00
char * destructor ; /* Code which executes whenever this symbol is
* * popped from the stack during error processing */
2016-08-16 16:46:40 +00:00
int destLineno ; /* Line number for start of destructor. Set to
* * - 1 for duplicate destructors . */
2000-05-29 14:26:00 +00:00
char * datatype ; /* The data type of information held by this
* * object . Only used if type = = NONTERMINAL */
int dtnum ; /* The data type number. In the parser, the value
* * stack is a union . The . yy % d element of this
* * union is the correct data type for this object */
2018-04-21 20:24:19 +00:00
int bContent ; /* True if this symbol ever carries content - if
* * it is ever more than just syntax */
2005-11-06 04:06:59 +00:00
/* The following fields are used by MULTITERMINALs only */
int nsubsym ; /* Number of constituent symbols in the MULTI */
struct symbol * * subsym ; /* Array of constituent symbols */
2000-05-29 14:26:00 +00:00
} ;
/* Each production rule in the grammar is stored in the following
* * structure . */
struct rule {
struct symbol * lhs ; /* Left-hand side of the rule */
2010-02-14 17:14:22 +00:00
const char * lhsalias ; /* Alias for the LHS (NULL if none) */
2007-10-05 16:16:36 +00:00
int lhsStart ; /* True if left-hand side is the start symbol */
2000-05-29 14:26:00 +00:00
int ruleline ; /* Line number for the rule */
int nrhs ; /* Number of RHS symbols */
struct symbol * * rhs ; /* The RHS symbols */
2010-02-14 17:14:22 +00:00
const char * * rhsalias ; /* An alias for each RHS symbol (NULL if none) */
2000-05-29 14:26:00 +00:00
int line ; /* Line number at which code begins */
2010-02-14 17:14:22 +00:00
const char * code ; /* The code executed when this rule is reduced */
2016-02-17 01:18:33 +00:00
const char * codePrefix ; /* Setup code before code[] above */
const char * codeSuffix ; /* Breakdown code after code[] above */
2000-05-29 14:26:00 +00:00
struct symbol * precsym ; /* Precedence symbol for this rule */
int index ; /* An index number for this rule */
2016-03-16 19:45:54 +00:00
int iRule ; /* Rule number as used in the generated tables */
2019-12-10 20:41:48 +00:00
Boolean noCode ; /* True if this rule has no associated C code */
Boolean codeEmitted ; /* True if the code has been emitted already */
2000-05-29 14:26:00 +00:00
Boolean canReduce ; /* True if this rule is ever reduced */
2016-05-24 18:55:08 +00:00
Boolean doesReduce ; /* Reduce actions occur after optimization */
2019-12-10 20:41:48 +00:00
Boolean neverReduce ; /* Reduce is theoretically possible, but prevented
* * by actions or other outside implementation */
2000-05-29 14:26:00 +00:00
struct rule * nextlhs ; /* Next rule with the same LHS */
struct rule * next ; /* Next rule in the global list */
} ;
/* A configuration is a production rule of the grammar together with
* * a mark ( dot ) showing how much of that rule has been processed so far .
* * Configurations also contain a follow - set which is a list of terminal
* * symbols which are allowed to immediately follow the end of the rule .
* * Every configuration is recorded as an instance of the following : */
2010-02-14 17:14:22 +00:00
enum cfgstatus {
COMPLETE ,
INCOMPLETE
} ;
2000-05-29 14:26:00 +00:00
struct config {
struct rule * rp ; /* The rule upon which the configuration is based */
int dot ; /* The parse point */
char * fws ; /* Follow-set for this configuration only */
struct plink * fplp ; /* Follow-set forward propagation links */
struct plink * bplp ; /* Follow-set backwards propagation links */
struct state * stp ; /* Pointer to state which contains this */
2010-02-14 17:14:22 +00:00
enum cfgstatus status ; /* used during followset and shift computations */
2000-05-29 14:26:00 +00:00
struct config * next ; /* Next configuration in the state */
struct config * bp ; /* The next basis configuration */
} ;
2010-02-14 17:14:22 +00:00
enum e_action {
SHIFT ,
ACCEPT ,
REDUCE ,
ERROR ,
SSCONFLICT , /* A shift/shift conflict */
SRCONFLICT , /* Was a reduce, but part of a conflict */
RRCONFLICT , /* Was a reduce, but part of a conflict */
SH_RESOLVED , /* Was a shift. Precedence resolved conflict */
RD_RESOLVED , /* Was reduce. Precedence resolved conflict */
2015-09-07 18:23:37 +00:00
NOT_USED , /* Deleted by compression */
SHIFTREDUCE /* Shift first, then reduce */
2010-02-14 17:14:22 +00:00
} ;
2000-05-29 14:26:00 +00:00
/* Every shift or reduce operation is stored as one of the following */
struct action {
struct symbol * sp ; /* The look-ahead symbol */
2010-02-14 17:14:22 +00:00
enum e_action type ;
2000-05-29 14:26:00 +00:00
union {
struct state * stp ; /* The new state, if a shift */
struct rule * rp ; /* The rule, if a reduce */
} x ;
2016-05-23 16:15:02 +00:00
struct symbol * spOpt ; /* SHIFTREDUCE optimization to this symbol */
2000-05-29 14:26:00 +00:00
struct action * next ; /* Next action for this state */
struct action * collide ; /* Next action with the same hash */
} ;
/* Each state of the generated parser's finite state machine
* * is encoded as an instance of the following structure . */
struct state {
struct config * bp ; /* The basis configurations for this state */
struct config * cfp ; /* All configurations in this set */
2008-07-14 12:27:51 +00:00
int statenum ; /* Sequential number for this state */
2016-05-23 14:24:31 +00:00
struct action * ap ; /* List of actions for this state */
2003-10-21 13:16:03 +00:00
int nTknAct , nNtAct ; /* Number of actions on terminals and nonterminals */
int iTknOfst , iNtOfst ; /* yy_action[] offset for terminals and nonterms */
2015-09-07 18:23:37 +00:00
int iDfltReduce ; /* Default action is to REDUCE by this rule */
struct rule * pDfltReduce ; /* The default REDUCE rule. */
int autoReduce ; /* True if this is an auto-reduce state */
2000-05-29 14:26:00 +00:00
} ;
2003-10-21 13:16:03 +00:00
# define NO_OFFSET (-2147483647)
2000-05-29 14:26:00 +00:00
/* A followset propagation link indicates that the contents of one
* * configuration followset should be propagated to another whenever
* * the first changes . */
struct plink {
struct config * cfp ; /* The configuration to which linked */
struct plink * next ; /* The next propagate link */
} ;
/* The state vector for the entire parser generator is recorded as
* * follows . ( LEMON uses no global variables and makes little use of
* * static variables . Fields in the following structure can be thought
* * of as begin global variables in the program . ) */
struct lemon {
struct state * * sorted ; /* Table of states sorted by state number */
struct rule * rule ; /* List of all rules */
2016-03-16 19:45:54 +00:00
struct rule * startRule ; /* First rule */
2000-05-29 14:26:00 +00:00
int nstate ; /* Number of states */
2015-09-07 18:23:37 +00:00
int nxstate ; /* nstate with tail degenerate states removed */
2000-05-29 14:26:00 +00:00
int nrule ; /* Number of rules */
2019-12-11 18:53:51 +00:00
int nruleWithAction ; /* Number of rules with actions */
2000-05-29 14:26:00 +00:00
int nsymbol ; /* Number of terminal and nonterminal symbols */
int nterminal ; /* Number of terminal symbols */
2017-12-24 23:38:10 +00:00
int minShiftReduce ; /* Minimum shift-reduce action value */
int errAction ; /* Error action value */
int accAction ; /* Accept action value */
int noAction ; /* No-op action value */
int minReduce ; /* Minimum reduce action */
int maxAction ; /* Maximum action value of any kind */
2000-05-29 14:26:00 +00:00
struct symbol * * symbols ; /* Sorted array of pointers to symbols */
int errorcnt ; /* Number of errors */
struct symbol * errsym ; /* The error symbol */
2006-06-10 13:29:31 +00:00
struct symbol * wildcard ; /* Token that matches anything */
2000-05-29 14:26:00 +00:00
char * name ; /* Name of the generated parser */
2021-01-07 16:10:14 +00:00
char * arg ; /* Declaration of the 3rd argument to parser */
2018-04-21 13:51:42 +00:00
char * ctx ; /* Declaration of 2nd argument to constructor */
2000-05-29 14:26:00 +00:00
char * tokentype ; /* Type of terminal symbols in the parser stack */
2001-04-03 16:53:21 +00:00
char * vartype ; /* The default type of non-terminal symbols */
2000-05-29 14:26:00 +00:00
char * start ; /* Name of the start symbol for the grammar */
char * stacksize ; /* Size of the parser stack */
char * include ; /* Code to put at the start of the C file */
char * error ; /* Code to execute when an error is seen */
char * overflow ; /* Code to execute on a stack overflow */
char * failure ; /* Code to execute on parser failure */
char * accept ; /* Code to execute when the parser excepts */
char * extracode ; /* Code appended to the generated file */
char * tokendest ; /* Code to execute to destroy token data */
2001-04-03 16:53:21 +00:00
char * vardest ; /* Code for the default non-terminal destructor */
2000-05-29 14:26:00 +00:00
char * filename ; /* Name of the input file */
char * outname ; /* Name of the current output file */
char * tokenprefix ; /* A prefix added to token names in the .h file */
int nconflict ; /* Number of parsing conflicts */
2015-09-07 02:23:02 +00:00
int nactiontab ; /* Number of entries in the yy_action[] table */
2017-12-25 04:15:38 +00:00
int nlookaheadtab ; /* Number of entries in yy_lookahead[] */
2015-09-07 02:23:02 +00:00
int tablesize ; /* Total table size of all tables in bytes */
2000-05-29 14:26:00 +00:00
int basisflag ; /* Print only basis configurations */
2020-07-03 15:41:08 +00:00
int printPreprocessed ; /* Show preprocessor output on stdout */
2008-07-14 12:27:51 +00:00
int has_fallback ; /* True if any %fallback is seen in the grammar */
2008-12-10 20:10:04 +00:00
int nolinenosflag ; /* True if #line statements should not be printed */
2023-06-08 12:52:28 +00:00
int argc ; /* Number of command-line arguments */
char * * argv ; /* Command-line arguments */
2000-05-29 14:26:00 +00:00
} ;
# define MemoryCheck(X) if((X)==0){ \
extern void memory_error ( ) ; \
memory_error ( ) ; \
}
/**************** From the file "table.h" *********************************/
/*
* * All code in this file has been automatically generated
* * from a specification in the file
* * " table.q "
* * by the associative array code building program " aagen " .
* * Do not edit this file ! Instead , edit the specification
* * file , then rerun aagen .
*/
/*
* * Code for processing tables in the LEMON parser generator .
*/
/* Routines for handling a strings */
2010-02-14 17:14:22 +00:00
const char * Strsafe ( const char * ) ;
2000-05-29 14:26:00 +00:00
2010-02-14 17:14:22 +00:00
void Strsafe_init ( void ) ;
int Strsafe_insert ( const char * ) ;
const char * Strsafe_find ( const char * ) ;
2000-05-29 14:26:00 +00:00
/* Routines for handling symbols of the grammar */
2010-02-14 17:14:22 +00:00
struct symbol * Symbol_new ( const char * ) ;
int Symbolcmpp ( const void * , const void * ) ;
void Symbol_init ( void ) ;
int Symbol_insert ( struct symbol * , const char * ) ;
struct symbol * Symbol_find ( const char * ) ;
struct symbol * Symbol_Nth ( int ) ;
int Symbol_count ( void ) ;
struct symbol * * Symbol_arrayof ( void ) ;
2000-05-29 14:26:00 +00:00
/* Routines to manage the state table */
2010-02-14 17:14:22 +00:00
int Configcmp ( const char * , const char * ) ;
struct state * State_new ( void ) ;
void State_init ( void ) ;
int State_insert ( struct state * , struct config * ) ;
struct state * State_find ( struct config * ) ;
2017-04-14 19:44:15 +00:00
struct state * * State_arrayof ( void ) ;
2000-05-29 14:26:00 +00:00
/* Routines used for efficiency in Configlist_add */
2010-02-14 17:14:22 +00:00
void Configtable_init ( void ) ;
int Configtable_insert ( struct config * ) ;
struct config * Configtable_find ( struct config * ) ;
void Configtable_clear ( int ( * ) ( struct config * ) ) ;
2000-05-29 14:26:00 +00:00
/****************** From the file "action.c" *******************************/
/*
* * Routines processing parser actions in the LEMON parser generator .
*/
/* Allocate a new parser action */
2007-07-18 18:16:29 +00:00
static struct action * Action_new ( void ) {
2019-05-10 16:16:19 +00:00
static struct action * actionfreelist = 0 ;
2010-02-14 17:14:22 +00:00
struct action * newaction ;
2000-05-29 14:26:00 +00:00
2019-05-10 16:16:19 +00:00
if ( actionfreelist = = 0 ) {
2000-05-29 14:26:00 +00:00
int i ;
int amt = 100 ;
2019-05-10 16:16:19 +00:00
actionfreelist = ( struct action * ) calloc ( amt , sizeof ( struct action ) ) ;
if ( actionfreelist = = 0 ) {
2000-05-29 14:26:00 +00:00
fprintf ( stderr , " Unable to allocate memory for a new parser action. " ) ;
exit ( 1 ) ;
}
2019-05-10 16:16:19 +00:00
for ( i = 0 ; i < amt - 1 ; i + + ) actionfreelist [ i ] . next = & actionfreelist [ i + 1 ] ;
actionfreelist [ amt - 1 ] . next = 0 ;
2000-05-29 14:26:00 +00:00
}
2019-05-10 16:16:19 +00:00
newaction = actionfreelist ;
actionfreelist = actionfreelist - > next ;
2010-02-14 17:14:22 +00:00
return newaction ;
2000-05-29 14:26:00 +00:00
}
2007-07-18 18:16:29 +00:00
/* Compare two actions for sorting purposes. Return negative, zero, or
* * positive if the first action is less than , equal to , or greater than
* * the first
*/
static int actioncmp (
struct action * ap1 ,
struct action * ap2
) {
2000-05-29 14:26:00 +00:00
int rc ;
rc = ap1 - > sp - > index - ap2 - > sp - > index ;
if ( rc = = 0 ) {
2007-12-21 00:02:11 +00:00
rc = ( int ) ap1 - > type - ( int ) ap2 - > type ;
}
2015-09-07 18:23:37 +00:00
if ( rc = = 0 & & ( ap1 - > type = = REDUCE | | ap1 - > type = = SHIFTREDUCE ) ) {
2000-05-29 14:26:00 +00:00
rc = ap1 - > x . rp - > index - ap2 - > x . rp - > index ;
}
2009-11-03 13:02:25 +00:00
if ( rc = = 0 ) {
2010-03-03 17:09:01 +00:00
rc = ( int ) ( ap2 - ap1 ) ;
2009-11-03 13:02:25 +00:00
}
2000-05-29 14:26:00 +00:00
return rc ;
}
/* Sort parser actions */
2007-07-18 18:16:29 +00:00
static struct action * Action_sort (
struct action * ap
) {
ap = ( struct action * ) msort ( ( char * ) ap , ( char * * ) & ap - > next ,
( int ( * ) ( const char * , const char * ) ) actioncmp ) ;
2000-05-29 14:26:00 +00:00
return ap ;
}
2010-02-14 17:14:22 +00:00
void Action_add (
struct action * * app ,
enum e_action type ,
struct symbol * sp ,
char * arg
) {
struct action * newaction ;
newaction = Action_new ( ) ;
newaction - > next = * app ;
* app = newaction ;
newaction - > type = type ;
newaction - > sp = sp ;
2016-05-23 16:15:02 +00:00
newaction - > spOpt = 0 ;
2000-05-29 14:26:00 +00:00
if ( type = = SHIFT ) {
2010-02-14 17:14:22 +00:00
newaction - > x . stp = ( struct state * ) arg ;
2000-05-29 14:26:00 +00:00
} else {
2010-02-14 17:14:22 +00:00
newaction - > x . rp = ( struct rule * ) arg ;
2000-05-29 14:26:00 +00:00
}
}
2003-10-21 13:16:03 +00:00
/********************** New code to implement the "acttab" module ***********/
/*
* * This module implements routines use to construct the yy_action [ ] table .
*/
/*
* * The state of the yy_action table under construction is an instance of
2010-01-07 03:53:03 +00:00
* * the following structure .
* *
* * The yy_action table maps the pair ( state_number , lookahead ) into an
* * action_number . The table is an array of integers pairs . The state_number
* * determines an initial offset into the yy_action array . The lookahead
* * value is then added to this initial offset to get an index X into the
* * yy_action array . If the aAction [ X ] . lookahead equals the value of the
* * of the lookahead input , then the value of the action_number output is
* * aAction [ X ] . action . If the lookaheads do not match then the
* * default action for the state_number is returned .
* *
* * All actions associated with a single state_number are first entered
2017-04-14 19:46:12 +00:00
* * into aLookahead [ ] using multiple calls to acttab_action ( ) . Then the
* * actions for that single state_number are placed into the aAction [ ]
2010-01-07 03:53:03 +00:00
* * array with a single call to acttab_insert ( ) . The acttab_insert ( ) call
* * also resets the aLookahead [ ] array in preparation for the next
* * state number .
2003-10-21 13:16:03 +00:00
*/
2010-02-14 17:14:22 +00:00
struct lookahead_action {
int lookahead ; /* Value of the lookahead token */
int action ; /* Action to take on the given lookahead */
} ;
2003-10-21 13:16:03 +00:00
typedef struct acttab acttab ;
struct acttab {
int nAction ; /* Number of used slots in aAction[] */
int nActionAlloc ; /* Slots allocated for aAction[] */
2010-02-14 17:14:22 +00:00
struct lookahead_action
* aAction , /* The yy_action[] table under construction */
2003-10-21 13:16:03 +00:00
* aLookahead ; /* A single new transaction set */
int mnLookahead ; /* Minimum aLookahead[].lookahead */
int mnAction ; /* Action associated with mnLookahead */
int mxLookahead ; /* Maximum aLookahead[].lookahead */
int nLookahead ; /* Used slots in aLookahead[] */
int nLookaheadAlloc ; /* Slots allocated in aLookahead[] */
2017-12-25 04:15:38 +00:00
int nterminal ; /* Number of terminal symbols */
int nsymbol ; /* total number of symbols */
2003-10-21 13:16:03 +00:00
} ;
/* Return the number of entries in the yy_action table */
2017-12-25 04:15:38 +00:00
# define acttab_lookahead_size(X) ((X)->nAction)
2003-10-21 13:16:03 +00:00
/* The value for the N-th entry in yy_action */
# define acttab_yyaction(X,N) ((X)->aAction[N].action)
/* The value for the N-th entry in yy_lookahead */
# define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead)
/* Free all memory associated with the given acttab */
void acttab_free ( acttab * p ) {
free ( p - > aAction ) ;
free ( p - > aLookahead ) ;
free ( p ) ;
}
/* Allocate a new acttab structure */
2017-12-25 04:15:38 +00:00
acttab * acttab_alloc ( int nsymbol , int nterminal ) {
2010-02-14 17:14:22 +00:00
acttab * p = ( acttab * ) calloc ( 1 , sizeof ( * p ) ) ;
2003-10-21 13:16:03 +00:00
if ( p = = 0 ) {
fprintf ( stderr , " Unable to allocate memory for a new acttab. " ) ;
exit ( 1 ) ;
}
memset ( p , 0 , sizeof ( * p ) ) ;
2017-12-25 04:15:38 +00:00
p - > nsymbol = nsymbol ;
p - > nterminal = nterminal ;
2003-10-21 13:16:03 +00:00
return p ;
}
2017-04-14 19:46:12 +00:00
/* Add a new action to the current transaction set.
2010-01-07 03:53:03 +00:00
* *
* * This routine is called once for each lookahead for a particular
* * state .
2003-10-21 13:16:03 +00:00
*/
void acttab_action ( acttab * p , int lookahead , int action ) {
if ( p - > nLookahead > = p - > nLookaheadAlloc ) {
p - > nLookaheadAlloc + = 25 ;
2010-02-14 17:14:22 +00:00
p - > aLookahead = ( struct lookahead_action * ) realloc ( p - > aLookahead ,
2003-10-21 13:16:03 +00:00
sizeof ( p - > aLookahead [ 0 ] ) * p - > nLookaheadAlloc ) ;
if ( p - > aLookahead = = 0 ) {
fprintf ( stderr , " malloc failed \n " ) ;
exit ( 1 ) ;
}
}
if ( p - > nLookahead = = 0 ) {
p - > mxLookahead = lookahead ;
p - > mnLookahead = lookahead ;
p - > mnAction = action ;
} else {
if ( p - > mxLookahead < lookahead ) p - > mxLookahead = lookahead ;
if ( p - > mnLookahead > lookahead ) {
p - > mnLookahead = lookahead ;
p - > mnAction = action ;
}
}
p - > aLookahead [ p - > nLookahead ] . lookahead = lookahead ;
p - > aLookahead [ p - > nLookahead ] . action = action ;
p - > nLookahead + + ;
}
/*
* * Add the transaction set built up with prior calls to acttab_action ( )
* * into the current action table . Then reset the transaction set back
* * to an empty set in preparation for a new round of acttab_action ( ) calls .
* *
* * Return the offset into the action table of the new transaction .
2017-12-25 04:15:38 +00:00
* *
* * If the makeItSafe parameter is true , then the offset is chosen so that
* * it is impossible to overread the yy_lookaside [ ] table regardless of
* * the lookaside token . This is done for the terminal symbols , as they
* * come from external inputs and can contain syntax errors . When makeItSafe
* * is false , there is more flexibility in selecting offsets , resulting in
* * a smaller table . For non - terminal symbols , which are never syntax errors ,
* * makeItSafe can be false .
2003-10-21 13:16:03 +00:00
*/
2017-12-25 04:15:38 +00:00
int acttab_insert ( acttab * p , int makeItSafe ) {
int i , j , k , n , end ;
2003-10-21 13:16:03 +00:00
assert ( p - > nLookahead > 0 ) ;
/* Make sure we have enough space to hold the expanded action table
* * in the worst case . The worst case occurs if the transaction set
* * must be appended to the current action table
*/
2017-12-25 04:15:38 +00:00
n = p - > nsymbol + 1 ;
2010-01-07 03:53:03 +00:00
if ( p - > nAction + n > = p - > nActionAlloc ) {
2003-10-21 16:34:41 +00:00
int oldAlloc = p - > nActionAlloc ;
2003-10-21 13:16:03 +00:00
p - > nActionAlloc = p - > nAction + n + p - > nActionAlloc + 20 ;
2010-02-14 17:14:22 +00:00
p - > aAction = ( struct lookahead_action * ) realloc ( p - > aAction ,
2003-10-21 13:16:03 +00:00
sizeof ( p - > aAction [ 0 ] ) * p - > nActionAlloc ) ;
if ( p - > aAction = = 0 ) {
fprintf ( stderr , " malloc failed \n " ) ;
exit ( 1 ) ;
}
2003-10-21 16:34:41 +00:00
for ( i = oldAlloc ; i < p - > nActionAlloc ; i + + ) {
2003-10-21 13:16:03 +00:00
p - > aAction [ i ] . lookahead = - 1 ;
p - > aAction [ i ] . action = - 1 ;
}
}
2017-04-14 19:46:12 +00:00
/* Scan the existing action table looking for an offset that is a
2010-01-07 03:53:03 +00:00
* * duplicate of the current transaction set . Fall out of the loop
* * if and when the duplicate is found .
2003-10-21 13:16:03 +00:00
* *
* * i is the index in p - > aAction [ ] where p - > mnLookahead is inserted .
*/
2017-12-25 04:15:38 +00:00
end = makeItSafe ? p - > mnLookahead : 0 ;
for ( i = p - > nAction - 1 ; i > = end ; i - - ) {
2009-11-03 19:18:31 +00:00
if ( p - > aAction [ i ] . lookahead = = p - > mnLookahead ) {
2010-01-07 03:53:03 +00:00
/* All lookaheads and actions in the aLookahead[] transaction
* * must match against the candidate aAction [ i ] entry . */
2003-10-21 13:16:03 +00:00
if ( p - > aAction [ i ] . action ! = p - > mnAction ) continue ;
for ( j = 0 ; j < p - > nLookahead ; j + + ) {
k = p - > aLookahead [ j ] . lookahead - p - > mnLookahead + i ;
if ( k < 0 | | k > = p - > nAction ) break ;
if ( p - > aLookahead [ j ] . lookahead ! = p - > aAction [ k ] . lookahead ) break ;
if ( p - > aLookahead [ j ] . action ! = p - > aAction [ k ] . action ) break ;
}
if ( j < p - > nLookahead ) continue ;
2010-01-07 03:53:03 +00:00
/* No possible lookahead value that is not in the aLookahead[]
* * transaction is allowed to match aAction [ i ] */
2003-10-21 13:16:03 +00:00
n = 0 ;
for ( j = 0 ; j < p - > nAction ; j + + ) {
2003-10-21 16:34:41 +00:00
if ( p - > aAction [ j ] . lookahead < 0 ) continue ;
if ( p - > aAction [ j ] . lookahead = = j + p - > mnLookahead - i ) n + + ;
}
if ( n = = p - > nLookahead ) {
2010-01-07 03:53:03 +00:00
break ; /* An exact match is found at offset i */
2003-10-21 13:16:03 +00:00
}
}
}
2010-01-07 03:53:03 +00:00
/* If no existing offsets exactly match the current transaction, find an
* * an empty offset in the aAction [ ] table in which we can add the
* * aLookahead [ ] transaction .
*/
2017-12-25 04:15:38 +00:00
if ( i < end ) {
2010-01-07 03:53:03 +00:00
/* Look for holes in the aAction[] table that fit the current
* * aLookahead [ ] transaction . Leave i set to the offset of the hole .
* * If no holes are found , i is left at p - > nAction , which means the
* * transaction will be appended . */
2017-12-25 04:15:38 +00:00
i = makeItSafe ? p - > mnLookahead : 0 ;
for ( ; i < p - > nActionAlloc - p - > mxLookahead ; i + + ) {
2009-11-03 19:18:31 +00:00
if ( p - > aAction [ i ] . lookahead < 0 ) {
for ( j = 0 ; j < p - > nLookahead ; j + + ) {
k = p - > aLookahead [ j ] . lookahead - p - > mnLookahead + i ;
if ( k < 0 ) break ;
if ( p - > aAction [ k ] . lookahead > = 0 ) break ;
}
if ( j < p - > nLookahead ) continue ;
for ( j = 0 ; j < p - > nAction ; j + + ) {
if ( p - > aAction [ j ] . lookahead = = j + p - > mnLookahead - i ) break ;
}
if ( j = = p - > nAction ) {
break ; /* Fits in empty slots */
}
}
}
}
2003-10-21 13:16:03 +00:00
/* Insert transaction set at index i. */
2017-12-25 04:15:38 +00:00
#if 0
printf ( " Acttab: " ) ;
for ( j = 0 ; j < p - > nLookahead ; j + + ) {
printf ( " %d " , p - > aLookahead [ j ] . lookahead ) ;
}
printf ( " inserted at %d \n " , i ) ;
# endif
2003-10-21 13:16:03 +00:00
for ( j = 0 ; j < p - > nLookahead ; j + + ) {
k = p - > aLookahead [ j ] . lookahead - p - > mnLookahead + i ;
p - > aAction [ k ] = p - > aLookahead [ j ] ;
if ( k > = p - > nAction ) p - > nAction = k + 1 ;
}
2017-12-27 15:21:16 +00:00
if ( makeItSafe & & i + p - > nterminal > = p - > nAction ) p - > nAction = i + p - > nterminal + 1 ;
2003-10-21 13:16:03 +00:00
p - > nLookahead = 0 ;
/* Return the offset that is added to the lookahead in order to get the
* * index into yy_action of the action */
return i - p - > mnLookahead ;
}
2017-12-25 04:15:38 +00:00
/*
* * Return the size of the action table without the trailing syntax error
* * entries .
*/
int acttab_action_size ( acttab * p ) {
int n = p - > nAction ;
while ( n > 0 & & p - > aAction [ n - 1 ] . lookahead < 0 ) { n - - ; }
return n ;
}
2000-05-29 14:26:00 +00:00
/********************** From the file "build.c" *****************************/
/*
* * Routines to construction the finite state machine for the LEMON
* * parser generator .
*/
/* Find a precedence symbol of every rule in the grammar.
2017-04-14 19:46:12 +00:00
* *
2000-05-29 14:26:00 +00:00
* * Those rules which have a precedence symbol coded in the input
* * grammar using the " [symbol] " construct will already have the
* * rp - > precsym field filled . Other rules take as their precedence
* * symbol the first RHS symbol with a defined precedence . If there
* * are not RHS symbols with a defined precedence , the precedence
* * symbol field is left blank .
*/
2010-02-14 17:14:22 +00:00
void FindRulePrecedences ( struct lemon * xp )
2000-05-29 14:26:00 +00:00
{
struct rule * rp ;
for ( rp = xp - > rule ; rp ; rp = rp - > next ) {
if ( rp - > precsym = = 0 ) {
2005-11-06 04:06:59 +00:00
int i , j ;
for ( i = 0 ; i < rp - > nrhs & & rp - > precsym = = 0 ; i + + ) {
struct symbol * sp = rp - > rhs [ i ] ;
if ( sp - > type = = MULTITERMINAL ) {
for ( j = 0 ; j < sp - > nsubsym ; j + + ) {
if ( sp - > subsym [ j ] - > prec > = 0 ) {
rp - > precsym = sp - > subsym [ j ] ;
break ;
}
}
} else if ( sp - > prec > = 0 ) {
2000-05-29 14:26:00 +00:00
rp - > precsym = rp - > rhs [ i ] ;
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
}
}
}
return ;
}
/* Find all nonterminals which will generate the empty string.
* * Then go back and compute the first sets of every nonterminal .
* * The first set is the set of all terminal symbols which can begin
* * a string generated by that nonterminal .
*/
2010-02-14 17:14:22 +00:00
void FindFirstSets ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
2005-11-06 04:06:59 +00:00
int i , j ;
2000-05-29 14:26:00 +00:00
struct rule * rp ;
int progress ;
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
2007-08-23 02:50:56 +00:00
lemp - > symbols [ i ] - > lambda = LEMON_FALSE ;
2000-05-29 14:26:00 +00:00
}
for ( i = lemp - > nterminal ; i < lemp - > nsymbol ; i + + ) {
lemp - > symbols [ i ] - > firstset = SetNew ( ) ;
}
/* First compute all lambdas */
do {
progress = 0 ;
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
if ( rp - > lhs - > lambda ) continue ;
for ( i = 0 ; i < rp - > nrhs ; i + + ) {
2012-01-07 15:17:18 +00:00
struct symbol * sp = rp - > rhs [ i ] ;
assert ( sp - > type = = NONTERMINAL | | sp - > lambda = = LEMON_FALSE ) ;
if ( sp - > lambda = = LEMON_FALSE ) break ;
2000-05-29 14:26:00 +00:00
}
if ( i = = rp - > nrhs ) {
2007-08-23 02:50:56 +00:00
rp - > lhs - > lambda = LEMON_TRUE ;
2000-05-29 14:26:00 +00:00
progress = 1 ;
}
}
} while ( progress ) ;
/* Now compute all first sets */
do {
struct symbol * s1 , * s2 ;
progress = 0 ;
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
s1 = rp - > lhs ;
for ( i = 0 ; i < rp - > nrhs ; i + + ) {
s2 = rp - > rhs [ i ] ;
if ( s2 - > type = = TERMINAL ) {
progress + = SetAdd ( s1 - > firstset , s2 - > index ) ;
break ;
2005-11-06 04:06:59 +00:00
} else if ( s2 - > type = = MULTITERMINAL ) {
for ( j = 0 ; j < s2 - > nsubsym ; j + + ) {
progress + = SetAdd ( s1 - > firstset , s2 - > subsym [ j ] - > index ) ;
}
break ;
2012-08-20 15:53:54 +00:00
} else if ( s1 = = s2 ) {
2007-08-23 02:50:56 +00:00
if ( s1 - > lambda = = LEMON_FALSE ) break ;
2012-08-20 15:53:54 +00:00
} else {
2000-05-29 14:26:00 +00:00
progress + = SetUnion ( s1 - > firstset , s2 - > firstset ) ;
2007-08-23 02:50:56 +00:00
if ( s2 - > lambda = = LEMON_FALSE ) break ;
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
}
}
} while ( progress ) ;
return ;
}
/* Compute all LR(0) states for the grammar. Links
* * are added to between some states so that the LR ( 1 ) follow sets
* * can be computed later .
*/
2010-02-14 17:14:22 +00:00
PRIVATE struct state * getstate ( struct lemon * ) ; /* forward reference */
void FindStates ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
struct symbol * sp ;
struct rule * rp ;
Configlist_init ( ) ;
/* Find the start symbol */
if ( lemp - > start ) {
sp = Symbol_find ( lemp - > start ) ;
if ( sp = = 0 ) {
ErrorMsg ( lemp - > filename , 0 ,
2019-12-12 00:20:40 +00:00
" The specified start symbol \" %s \" is not "
" in a nonterminal of the grammar. \" %s \" will be used as the start "
" symbol instead. " , lemp - > start , lemp - > startRule - > lhs - > name ) ;
2000-05-29 14:26:00 +00:00
lemp - > errorcnt + + ;
2016-03-16 19:45:54 +00:00
sp = lemp - > startRule - > lhs ;
2000-05-29 14:26:00 +00:00
}
2021-10-04 16:14:51 +00:00
} else if ( lemp - > startRule ) {
2016-03-16 19:45:54 +00:00
sp = lemp - > startRule - > lhs ;
2021-10-04 16:14:51 +00:00
} else {
ErrorMsg ( lemp - > filename , 0 , " Internal error - no start rule \n " ) ;
exit ( 1 ) ;
2000-05-29 14:26:00 +00:00
}
/* Make sure the start symbol doesn't occur on the right-hand side of
* * any rule . Report an error if it does . ( YACC would generate a new
* * start symbol in this case . ) */
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
int i ;
for ( i = 0 ; i < rp - > nrhs ; i + + ) {
2005-11-06 04:06:59 +00:00
if ( rp - > rhs [ i ] = = sp ) { /* FIX ME: Deal with multiterminals */
2000-05-29 14:26:00 +00:00
ErrorMsg ( lemp - > filename , 0 ,
2019-12-12 00:20:40 +00:00
" The start symbol \" %s \" occurs on the "
" right-hand side of a rule. This will result in a parser which "
" does not work properly. " , sp - > name ) ;
2000-05-29 14:26:00 +00:00
lemp - > errorcnt + + ;
}
}
}
/* The basis configuration set for the first state
* * is all rules which have the start symbol as their
* * left - hand side */
for ( rp = sp - > rule ; rp ; rp = rp - > nextlhs ) {
struct config * newcfp ;
2007-10-05 16:16:36 +00:00
rp - > lhsStart = 1 ;
2000-05-29 14:26:00 +00:00
newcfp = Configlist_addbasis ( rp , 0 ) ;
SetAdd ( newcfp - > fws , 0 ) ;
}
/* Compute the first state. All other states will be
* * computed automatically during the computation of the first one .
* * The returned pointer to the first state is not used . */
( void ) getstate ( lemp ) ;
return ;
}
/* Return a pointer to a state which is described by the configuration
* * list which has been built from calls to Configlist_add .
*/
2010-02-14 17:14:22 +00:00
PRIVATE void buildshifts ( struct lemon * , struct state * ) ; /* Forwd ref */
PRIVATE struct state * getstate ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
struct config * cfp , * bp ;
struct state * stp ;
/* Extract the sorted basis of the new state. The basis was constructed
* * by prior calls to " Configlist_addbasis() " . */
Configlist_sortbasis ( ) ;
bp = Configlist_basis ( ) ;
/* Get a state with the same basis */
stp = State_find ( bp ) ;
if ( stp ) {
/* A state with the same basis already exists! Copy all the follow-set
* * propagation links from the state under construction into the
* * preexisting state , then return a pointer to the preexisting state */
struct config * x , * y ;
for ( x = bp , y = stp - > bp ; x & & y ; x = x - > bp , y = y - > bp ) {
Plink_copy ( & y - > bplp , x - > bplp ) ;
Plink_delete ( x - > fplp ) ;
x - > fplp = x - > bplp = 0 ;
}
cfp = Configlist_return ( ) ;
Configlist_eat ( cfp ) ;
} else {
/* This really is a new state. Construct all the details */
Configlist_closure ( lemp ) ; /* Compute the configuration closure */
Configlist_sort ( ) ; /* Sort the configuration closure */
cfp = Configlist_return ( ) ; /* Get a pointer to the config list */
stp = State_new ( ) ; /* A new state structure */
MemoryCheck ( stp ) ;
stp - > bp = bp ; /* Remember the configuration basis */
stp - > cfp = cfp ; /* Remember the configuration closure */
2005-11-05 15:03:59 +00:00
stp - > statenum = lemp - > nstate + + ; /* Every state gets a sequence number */
2000-05-29 14:26:00 +00:00
stp - > ap = 0 ; /* No actions, yet. */
State_insert ( stp , stp - > bp ) ; /* Add to the state table */
buildshifts ( lemp , stp ) ; /* Recursively compute successor states */
}
return stp ;
}
2005-11-06 04:06:59 +00:00
/*
* * Return true if two symbols are the same .
*/
2010-02-14 17:14:22 +00:00
int same_symbol ( struct symbol * a , struct symbol * b )
2005-11-06 04:06:59 +00:00
{
int i ;
if ( a = = b ) return 1 ;
if ( a - > type ! = MULTITERMINAL ) return 0 ;
if ( b - > type ! = MULTITERMINAL ) return 0 ;
if ( a - > nsubsym ! = b - > nsubsym ) return 0 ;
for ( i = 0 ; i < a - > nsubsym ; i + + ) {
if ( a - > subsym [ i ] ! = b - > subsym [ i ] ) return 0 ;
}
return 1 ;
}
2000-05-29 14:26:00 +00:00
/* Construct all successor states to the given state. A "successor"
* * state is any state which can be reached by a shift action .
*/
2010-02-14 17:14:22 +00:00
PRIVATE void buildshifts ( struct lemon * lemp , struct state * stp )
2000-05-29 14:26:00 +00:00
{
struct config * cfp ; /* For looping thru the config closure of "stp" */
struct config * bcfp ; /* For the inner loop on config closure of "stp" */
2010-02-14 17:14:22 +00:00
struct config * newcfg ; /* */
2000-05-29 14:26:00 +00:00
struct symbol * sp ; /* Symbol following the dot in configuration "cfp" */
struct symbol * bsp ; /* Symbol following the dot in configuration "bcfp" */
struct state * newstp ; /* A pointer to a successor state */
2021-01-07 16:10:14 +00:00
/* Each configuration becomes complete after it contributes to a successor
2000-05-29 14:26:00 +00:00
* * state . Initially , all configurations are incomplete */
for ( cfp = stp - > cfp ; cfp ; cfp = cfp - > next ) cfp - > status = INCOMPLETE ;
/* Loop through all configurations of the state "stp" */
for ( cfp = stp - > cfp ; cfp ; cfp = cfp - > next ) {
if ( cfp - > status = = COMPLETE ) continue ; /* Already used by inner loop */
if ( cfp - > dot > = cfp - > rp - > nrhs ) continue ; /* Can't shift this config */
Configlist_reset ( ) ; /* Reset the new config set */
sp = cfp - > rp - > rhs [ cfp - > dot ] ; /* Symbol after the dot */
/* For every configuration in the state "stp" which has the symbol "sp"
* * following its dot , add the same configuration to the basis set under
* * construction but with the dot shifted one symbol to the right . */
for ( bcfp = cfp ; bcfp ; bcfp = bcfp - > next ) {
if ( bcfp - > status = = COMPLETE ) continue ; /* Already used */
if ( bcfp - > dot > = bcfp - > rp - > nrhs ) continue ; /* Can't shift this one */
bsp = bcfp - > rp - > rhs [ bcfp - > dot ] ; /* Get symbol after dot */
2005-11-06 04:06:59 +00:00
if ( ! same_symbol ( bsp , sp ) ) continue ; /* Must be same as for "cfp" */
2000-05-29 14:26:00 +00:00
bcfp - > status = COMPLETE ; /* Mark this config as used */
2010-02-14 17:14:22 +00:00
newcfg = Configlist_addbasis ( bcfp - > rp , bcfp - > dot + 1 ) ;
Plink_add ( & newcfg - > bplp , bcfp ) ;
2000-05-29 14:26:00 +00:00
}
/* Get a pointer to the state described by the basis configuration set
* * constructed in the preceding loop */
newstp = getstate ( lemp ) ;
/* The state "newstp" is reached from the state "stp" by a shift action
* * on the symbol " sp " */
2005-11-06 04:06:59 +00:00
if ( sp - > type = = MULTITERMINAL ) {
int i ;
for ( i = 0 ; i < sp - > nsubsym ; i + + ) {
Action_add ( & stp - > ap , SHIFT , sp - > subsym [ i ] , ( char * ) newstp ) ;
}
} else {
Action_add ( & stp - > ap , SHIFT , sp , ( char * ) newstp ) ;
}
2000-05-29 14:26:00 +00:00
}
}
/*
* * Construct the propagation links
*/
2010-02-14 17:14:22 +00:00
void FindLinks ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
int i ;
struct config * cfp , * other ;
struct state * stp ;
struct plink * plp ;
/* Housekeeping detail:
* * Add to every propagate link a pointer back to the state to
* * which the link is attached . */
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
stp = lemp - > sorted [ i ] ;
2021-10-04 16:14:51 +00:00
for ( cfp = stp ? stp - > cfp : 0 ; cfp ; cfp = cfp - > next ) {
2000-05-29 14:26:00 +00:00
cfp - > stp = stp ;
}
}
/* Convert all backlinks into forward links. Only the forward
* * links are used in the follow - set computation . */
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
stp = lemp - > sorted [ i ] ;
2021-10-04 16:14:51 +00:00
for ( cfp = stp ? stp - > cfp : 0 ; cfp ; cfp = cfp - > next ) {
2000-05-29 14:26:00 +00:00
for ( plp = cfp - > bplp ; plp ; plp = plp - > next ) {
other = plp - > cfp ;
Plink_add ( & other - > fplp , cfp ) ;
}
}
}
}
/* Compute all followsets.
* *
* * A followset is the set of all symbols which can come immediately
* * after a configuration .
*/
2010-02-14 17:14:22 +00:00
void FindFollowSets ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
int i ;
struct config * cfp ;
struct plink * plp ;
int progress ;
int change ;
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
2021-10-04 16:14:51 +00:00
assert ( lemp - > sorted [ i ] ! = 0 ) ;
2000-05-29 14:26:00 +00:00
for ( cfp = lemp - > sorted [ i ] - > cfp ; cfp ; cfp = cfp - > next ) {
cfp - > status = INCOMPLETE ;
}
}
2017-04-14 19:46:12 +00:00
2000-05-29 14:26:00 +00:00
do {
progress = 0 ;
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
2021-10-04 16:14:51 +00:00
assert ( lemp - > sorted [ i ] ! = 0 ) ;
2000-05-29 14:26:00 +00:00
for ( cfp = lemp - > sorted [ i ] - > cfp ; cfp ; cfp = cfp - > next ) {
if ( cfp - > status = = COMPLETE ) continue ;
for ( plp = cfp - > fplp ; plp ; plp = plp - > next ) {
change = SetUnion ( plp - > cfp - > fws , cfp - > fws ) ;
if ( change ) {
plp - > cfp - > status = INCOMPLETE ;
progress = 1 ;
2012-08-20 15:53:54 +00:00
}
}
2000-05-29 14:26:00 +00:00
cfp - > status = COMPLETE ;
}
}
} while ( progress ) ;
}
2012-01-09 14:19:05 +00:00
static int resolve_conflict ( struct action * , struct action * ) ;
2000-05-29 14:26:00 +00:00
/* Compute the reduce actions, and resolve conflicts.
*/
2010-02-14 17:14:22 +00:00
void FindActions ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
int i , j ;
struct config * cfp ;
struct state * stp ;
struct symbol * sp ;
struct rule * rp ;
2017-04-14 19:46:12 +00:00
/* Add all of the reduce actions
2000-05-29 14:26:00 +00:00
* * A reduce action is added for each element of the followset of
* * a configuration which has its dot at the extreme right .
*/
for ( i = 0 ; i < lemp - > nstate ; i + + ) { /* Loop over all states */
stp = lemp - > sorted [ i ] ;
for ( cfp = stp - > cfp ; cfp ; cfp = cfp - > next ) { /* Loop over all configurations */
if ( cfp - > rp - > nrhs = = cfp - > dot ) { /* Is dot at extreme right? */
for ( j = 0 ; j < lemp - > nterminal ; j + + ) {
if ( SetFind ( cfp - > fws , j ) ) {
/* Add a reduce action to the state "stp" which will reduce by the
* * rule " cfp->rp " if the lookahead symbol is " lemp->symbols[j] " */
2004-05-31 23:13:45 +00:00
Action_add ( & stp - > ap , REDUCE , lemp - > symbols [ j ] , ( char * ) cfp - > rp ) ;
2000-05-29 14:26:00 +00:00
}
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
}
}
}
/* Add the accepting token */
if ( lemp - > start ) {
sp = Symbol_find ( lemp - > start ) ;
2021-10-04 16:14:51 +00:00
if ( sp = = 0 ) {
if ( lemp - > startRule = = 0 ) {
fprintf ( stderr , " internal error on source line %d: no start rule \n " ,
__LINE__ ) ;
exit ( 1 ) ;
}
sp = lemp - > startRule - > lhs ;
}
2000-05-29 14:26:00 +00:00
} else {
2016-03-16 19:45:54 +00:00
sp = lemp - > startRule - > lhs ;
2000-05-29 14:26:00 +00:00
}
/* Add to the first state (which is always the starting state of the
* * finite state machine ) an action to ACCEPT if the lookahead is the
* * start nonterminal . */
Action_add ( & lemp - > sorted [ 0 ] - > ap , ACCEPT , sp , 0 ) ;
/* Resolve conflicts */
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
struct action * ap , * nap ;
stp = lemp - > sorted [ i ] ;
2007-07-18 18:16:29 +00:00
/* assert( stp->ap ); */
2000-05-29 14:26:00 +00:00
stp - > ap = Action_sort ( stp - > ap ) ;
2002-02-23 18:45:13 +00:00
for ( ap = stp - > ap ; ap & & ap - > next ; ap = ap - > next ) {
2000-05-29 14:26:00 +00:00
for ( nap = ap - > next ; nap & & nap - > sp = = ap - > sp ; nap = nap - > next ) {
/* The two actions "ap" and "nap" have the same lookahead.
* * Figure out which one should be used */
2012-01-09 14:19:05 +00:00
lemp - > nconflict + = resolve_conflict ( ap , nap ) ;
2000-05-29 14:26:00 +00:00
}
}
}
/* Report an error for each rule that can never be reduced. */
2007-08-23 02:50:56 +00:00
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) rp - > canReduce = LEMON_FALSE ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
struct action * ap ;
for ( ap = lemp - > sorted [ i ] - > ap ; ap ; ap = ap - > next ) {
2007-08-23 02:50:56 +00:00
if ( ap - > type = = REDUCE ) ap - > x . rp - > canReduce = LEMON_TRUE ;
2000-05-29 14:26:00 +00:00
}
}
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
if ( rp - > canReduce ) continue ;
ErrorMsg ( lemp - > filename , rp - > ruleline , " This rule can not be reduced. \n " ) ;
lemp - > errorcnt + + ;
}
}
/* Resolve a conflict between the two given actions. If the
2008-07-14 12:27:51 +00:00
* * conflict can ' t be resolved , return non - zero .
2000-05-29 14:26:00 +00:00
* *
* * NO LONGER TRUE :
* * To resolve a conflict , first look to see if either action
* * is on an error rule . In that case , take the action which
* * is not associated with the error rule . If neither or both
* * actions are associated with an error rule , then try to
* * use precedence to resolve the conflict .
* *
* * If either action is a SHIFT , then it must be apx . This
* * function won ' t work if apx - > type = = REDUCE and apy - > type = = SHIFT .
*/
2010-02-14 17:14:22 +00:00
static int resolve_conflict (
struct action * apx ,
2012-01-09 14:19:05 +00:00
struct action * apy
2010-02-14 17:14:22 +00:00
) {
2000-05-29 14:26:00 +00:00
struct symbol * spx , * spy ;
int errcnt = 0 ;
assert ( apx - > sp = = apy - > sp ) ; /* Otherwise there would be no conflict */
2006-12-14 01:06:22 +00:00
if ( apx - > type = = SHIFT & & apy - > type = = SHIFT ) {
2007-12-21 00:02:11 +00:00
apy - > type = SSCONFLICT ;
2006-12-14 01:06:22 +00:00
errcnt + + ;
}
2000-05-29 14:26:00 +00:00
if ( apx - > type = = SHIFT & & apy - > type = = REDUCE ) {
spx = apx - > sp ;
spy = apy - > x . rp - > precsym ;
if ( spy = = 0 | | spx - > prec < 0 | | spy - > prec < 0 ) {
/* Not enough precedence information. */
2007-12-21 00:02:11 +00:00
apy - > type = SRCONFLICT ;
2000-05-29 14:26:00 +00:00
errcnt + + ;
2010-07-19 01:52:07 +00:00
} else if ( spx - > prec > spy - > prec ) { /* higher precedence wins */
2000-05-29 14:26:00 +00:00
apy - > type = RD_RESOLVED ;
} else if ( spx - > prec < spy - > prec ) {
apx - > type = SH_RESOLVED ;
} else if ( spx - > prec = = spy - > prec & & spx - > assoc = = RIGHT ) { /* Use operator */
apy - > type = RD_RESOLVED ; /* associativity */
} else if ( spx - > prec = = spy - > prec & & spx - > assoc = = LEFT ) { /* to break tie */
apx - > type = SH_RESOLVED ;
} else {
assert ( spx - > prec = = spy - > prec & & spx - > assoc = = NONE ) ;
2014-06-09 13:11:40 +00:00
apx - > type = ERROR ;
2000-05-29 14:26:00 +00:00
}
} else if ( apx - > type = = REDUCE & & apy - > type = = REDUCE ) {
spx = apx - > x . rp - > precsym ;
spy = apy - > x . rp - > precsym ;
if ( spx = = 0 | | spy = = 0 | | spx - > prec < 0 | |
spy - > prec < 0 | | spx - > prec = = spy - > prec ) {
2007-12-21 00:02:11 +00:00
apy - > type = RRCONFLICT ;
2000-05-29 14:26:00 +00:00
errcnt + + ;
} else if ( spx - > prec > spy - > prec ) {
apy - > type = RD_RESOLVED ;
} else if ( spx - > prec < spy - > prec ) {
apx - > type = RD_RESOLVED ;
}
} else {
2017-04-14 19:46:12 +00:00
assert (
2002-02-23 18:45:13 +00:00
apx - > type = = SH_RESOLVED | |
apx - > type = = RD_RESOLVED | |
2007-12-21 00:02:11 +00:00
apx - > type = = SSCONFLICT | |
apx - > type = = SRCONFLICT | |
apx - > type = = RRCONFLICT | |
2002-02-23 18:45:13 +00:00
apy - > type = = SH_RESOLVED | |
apy - > type = = RD_RESOLVED | |
2007-12-21 00:02:11 +00:00
apy - > type = = SSCONFLICT | |
apy - > type = = SRCONFLICT | |
apy - > type = = RRCONFLICT
2002-02-23 18:45:13 +00:00
) ;
/* The REDUCE/SHIFT case cannot happen because SHIFTs come before
* * REDUCEs on the list . If we reach this point it must be because
* * the parser conflict had already been resolved . */
2000-05-29 14:26:00 +00:00
}
return errcnt ;
}
/********************* From the file "configlist.c" *************************/
/*
* * Routines to processing a configuration list and building a state
* * in the LEMON parser generator .
*/
static struct config * freelist = 0 ; /* List of free configurations */
static struct config * current = 0 ; /* Top of list of configurations */
static struct config * * currentend = 0 ; /* Last on list of configs */
static struct config * basis = 0 ; /* Top of list of basis configs */
static struct config * * basisend = 0 ; /* End of list of basis configs */
/* Return a pointer to a new configuration */
2017-04-14 19:44:15 +00:00
PRIVATE struct config * newconfig ( void ) {
2021-10-04 16:14:51 +00:00
return ( struct config * ) calloc ( 1 , sizeof ( struct config ) ) ;
2000-05-29 14:26:00 +00:00
}
/* The configuration "old" is no longer used */
2010-02-14 17:14:22 +00:00
PRIVATE void deleteconfig ( struct config * old )
2000-05-29 14:26:00 +00:00
{
old - > next = freelist ;
freelist = old ;
}
/* Initialized the configuration list builder */
2017-04-14 19:44:15 +00:00
void Configlist_init ( void ) {
2000-05-29 14:26:00 +00:00
current = 0 ;
currentend = & current ;
basis = 0 ;
basisend = & basis ;
Configtable_init ( ) ;
return ;
}
/* Initialized the configuration list builder */
2017-04-14 19:44:15 +00:00
void Configlist_reset ( void ) {
2000-05-29 14:26:00 +00:00
current = 0 ;
currentend = & current ;
basis = 0 ;
basisend = & basis ;
Configtable_clear ( 0 ) ;
return ;
}
/* Add another configuration to the configuration list */
2010-02-14 17:14:22 +00:00
struct config * Configlist_add (
struct rule * rp , /* The rule */
int dot /* Index into the RHS of the rule where the dot goes */
) {
2000-05-29 14:26:00 +00:00
struct config * cfp , model ;
assert ( currentend ! = 0 ) ;
model . rp = rp ;
model . dot = dot ;
cfp = Configtable_find ( & model ) ;
if ( cfp = = 0 ) {
cfp = newconfig ( ) ;
cfp - > rp = rp ;
cfp - > dot = dot ;
cfp - > fws = SetNew ( ) ;
cfp - > stp = 0 ;
cfp - > fplp = cfp - > bplp = 0 ;
cfp - > next = 0 ;
cfp - > bp = 0 ;
* currentend = cfp ;
currentend = & cfp - > next ;
Configtable_insert ( cfp ) ;
}
return cfp ;
}
/* Add a basis configuration to the configuration list */
2010-02-14 17:14:22 +00:00
struct config * Configlist_addbasis ( struct rule * rp , int dot )
2000-05-29 14:26:00 +00:00
{
struct config * cfp , model ;
assert ( basisend ! = 0 ) ;
assert ( currentend ! = 0 ) ;
model . rp = rp ;
model . dot = dot ;
cfp = Configtable_find ( & model ) ;
if ( cfp = = 0 ) {
cfp = newconfig ( ) ;
cfp - > rp = rp ;
cfp - > dot = dot ;
cfp - > fws = SetNew ( ) ;
cfp - > stp = 0 ;
cfp - > fplp = cfp - > bplp = 0 ;
cfp - > next = 0 ;
cfp - > bp = 0 ;
* currentend = cfp ;
currentend = & cfp - > next ;
* basisend = cfp ;
basisend = & cfp - > bp ;
Configtable_insert ( cfp ) ;
}
return cfp ;
}
/* Compute the closure of the configuration list */
2010-02-14 17:14:22 +00:00
void Configlist_closure ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
struct config * cfp , * newcfp ;
struct rule * rp , * newrp ;
struct symbol * sp , * xsp ;
int i , dot ;
assert ( currentend ! = 0 ) ;
for ( cfp = current ; cfp ; cfp = cfp - > next ) {
rp = cfp - > rp ;
dot = cfp - > dot ;
if ( dot > = rp - > nrhs ) continue ;
sp = rp - > rhs [ dot ] ;
if ( sp - > type = = NONTERMINAL ) {
if ( sp - > rule = = 0 & & sp ! = lemp - > errsym ) {
ErrorMsg ( lemp - > filename , rp - > line , " Nonterminal \" %s \" has no rules. " ,
sp - > name ) ;
lemp - > errorcnt + + ;
}
for ( newrp = sp - > rule ; newrp ; newrp = newrp - > nextlhs ) {
newcfp = Configlist_add ( newrp , 0 ) ;
for ( i = dot + 1 ; i < rp - > nrhs ; i + + ) {
xsp = rp - > rhs [ i ] ;
if ( xsp - > type = = TERMINAL ) {
SetAdd ( newcfp - > fws , xsp - > index ) ;
break ;
2005-11-06 04:06:59 +00:00
} else if ( xsp - > type = = MULTITERMINAL ) {
int k ;
for ( k = 0 ; k < xsp - > nsubsym ; k + + ) {
SetAdd ( newcfp - > fws , xsp - > subsym [ k ] - > index ) ;
}
break ;
2012-08-20 15:53:54 +00:00
} else {
2000-05-29 14:26:00 +00:00
SetUnion ( newcfp - > fws , xsp - > firstset ) ;
2007-08-23 02:50:56 +00:00
if ( xsp - > lambda = = LEMON_FALSE ) break ;
2012-08-20 15:53:54 +00:00
}
}
2000-05-29 14:26:00 +00:00
if ( i = = rp - > nrhs ) Plink_add ( & cfp - > fplp , newcfp ) ;
}
}
}
return ;
}
/* Sort the configuration list */
2017-04-14 19:44:15 +00:00
void Configlist_sort ( void ) {
2015-09-04 18:03:45 +00:00
current = ( struct config * ) msort ( ( char * ) current , ( char * * ) & ( current - > next ) ,
Configcmp ) ;
2000-05-29 14:26:00 +00:00
currentend = 0 ;
return ;
}
/* Sort the basis configuration list */
2017-04-14 19:44:15 +00:00
void Configlist_sortbasis ( void ) {
2015-09-04 18:03:45 +00:00
basis = ( struct config * ) msort ( ( char * ) current , ( char * * ) & ( current - > bp ) ,
Configcmp ) ;
2000-05-29 14:26:00 +00:00
basisend = 0 ;
return ;
}
/* Return a pointer to the head of the configuration list and
* * reset the list */
2017-04-14 19:44:15 +00:00
struct config * Configlist_return ( void ) {
2000-05-29 14:26:00 +00:00
struct config * old ;
old = current ;
current = 0 ;
currentend = 0 ;
return old ;
}
/* Return a pointer to the head of the configuration list and
* * reset the list */
2017-04-14 19:44:15 +00:00
struct config * Configlist_basis ( void ) {
2000-05-29 14:26:00 +00:00
struct config * old ;
old = basis ;
basis = 0 ;
basisend = 0 ;
return old ;
}
/* Free all elements of the given configuration list */
2010-02-14 17:14:22 +00:00
void Configlist_eat ( struct config * cfp )
2000-05-29 14:26:00 +00:00
{
struct config * nextcfp ;
for ( ; cfp ; cfp = nextcfp ) {
nextcfp = cfp - > next ;
assert ( cfp - > fplp = = 0 ) ;
assert ( cfp - > bplp = = 0 ) ;
if ( cfp - > fws ) SetFree ( cfp - > fws ) ;
deleteconfig ( cfp ) ;
}
return ;
}
/***************** From the file "error.c" *********************************/
/*
* * Code for printing error message .
*/
2003-04-15 01:49:48 +00:00
void ErrorMsg ( const char * filename , int lineno , const char * format , . . . ) {
2010-02-16 16:07:28 +00:00
va_list ap ;
2010-02-15 00:01:04 +00:00
fprintf ( stderr , " %s:%d: " , filename , lineno ) ;
va_start ( ap , format ) ;
vfprintf ( stderr , format , ap ) ;
va_end ( ap ) ;
fprintf ( stderr , " \n " ) ;
2000-05-29 14:26:00 +00:00
}
/**************** From the file "main.c" ************************************/
/*
* * Main program file for the LEMON parser generator .
*/
/* Report an out-of-memory condition and abort. This function
* * is used mostly by the " MemoryCheck " macro in struct . h
*/
2017-04-14 19:44:15 +00:00
void memory_error ( void ) {
2000-05-29 14:26:00 +00:00
fprintf ( stderr , " Out of memory. Aborting... \n " ) ;
exit ( 1 ) ;
}
2023-06-08 12:52:28 +00:00
static int nDefine = 0 ; /* Number of -D options on the command line */
static int nDefineUsed = 0 ; /* Number of -D options actually used */
static char * * azDefine = 0 ; /* Name of the -D macros */
static char * bDefineUsed = 0 ; /* True for every -D macro actually used */
2004-07-20 12:45:22 +00:00
/* This routine is called with the argument to each -D command-line option.
* * Add the macro defined to the azDefine array .
*/
static void handle_D_option ( char * z ) {
char * * paz ;
nDefine + + ;
2010-02-14 17:14:22 +00:00
azDefine = ( char * * ) realloc ( azDefine , sizeof ( azDefine [ 0 ] ) * nDefine ) ;
2004-07-20 12:45:22 +00:00
if ( azDefine = = 0 ) {
fprintf ( stderr , " out of memory \n " ) ;
exit ( 1 ) ;
}
2023-06-08 12:52:28 +00:00
bDefineUsed = ( char * ) realloc ( bDefineUsed , nDefine ) ;
if ( bDefineUsed = = 0 ) {
fprintf ( stderr , " out of memory \n " ) ;
exit ( 1 ) ;
}
bDefineUsed [ nDefine - 1 ] = 0 ;
2004-07-20 12:45:22 +00:00
paz = & azDefine [ nDefine - 1 ] ;
2010-02-14 17:14:22 +00:00
* paz = ( char * ) malloc ( lemonStrlen ( z ) + 1 ) ;
2004-07-20 12:45:22 +00:00
if ( * paz = = 0 ) {
fprintf ( stderr , " out of memory \n " ) ;
exit ( 1 ) ;
}
2014-01-10 23:21:00 +00:00
lemon_strcpy ( * paz , z ) ;
2004-07-20 12:45:22 +00:00
for ( z = * paz ; * z & & * z ! = ' = ' ; z + + ) { }
* z = 0 ;
}
2018-04-20 20:47:49 +00:00
/* Rember the name of the output directory
*/
static char * outputDir = NULL ;
static void handle_d_option ( char * z ) {
outputDir = ( char * ) malloc ( lemonStrlen ( z ) + 1 ) ;
if ( outputDir = = 0 ) {
fprintf ( stderr , " out of memory \n " ) ;
exit ( 1 ) ;
}
lemon_strcpy ( outputDir , z ) ;
}
2010-02-14 00:48:49 +00:00
static char * user_templatename = NULL ;
static void handle_T_option ( char * z ) {
2010-02-14 17:14:22 +00:00
user_templatename = ( char * ) malloc ( lemonStrlen ( z ) + 1 ) ;
2010-02-14 00:48:49 +00:00
if ( user_templatename = = 0 ) {
memory_error ( ) ;
}
2014-01-10 23:21:00 +00:00
lemon_strcpy ( user_templatename , z ) ;
2010-02-14 00:48:49 +00:00
}
2000-05-29 14:26:00 +00:00
2016-05-23 14:24:31 +00:00
/* Merge together to lists of rules ordered by rule.iRule */
2016-03-16 19:45:54 +00:00
static struct rule * Rule_merge ( struct rule * pA , struct rule * pB ) {
struct rule * pFirst = 0 ;
struct rule * * ppPrev = & pFirst ;
while ( pA & & pB ) {
if ( pA - > iRule < pB - > iRule ) {
* ppPrev = pA ;
ppPrev = & pA - > next ;
pA = pA - > next ;
} else {
* ppPrev = pB ;
ppPrev = & pB - > next ;
pB = pB - > next ;
}
}
if ( pA ) {
* ppPrev = pA ;
} else {
* ppPrev = pB ;
}
return pFirst ;
}
/*
* * Sort a list of rules in order of increasing iRule value
*/
static struct rule * Rule_sort ( struct rule * rp ) {
2020-09-16 16:55:56 +00:00
unsigned int i ;
2016-03-16 19:45:54 +00:00
struct rule * pNext ;
struct rule * x [ 32 ] ;
memset ( x , 0 , sizeof ( x ) ) ;
while ( rp ) {
pNext = rp - > next ;
rp - > next = 0 ;
2020-09-20 12:10:28 +00:00
for ( i = 0 ; i < sizeof ( x ) / sizeof ( x [ 0 ] ) - 1 & & x [ i ] ; i + + ) {
2016-03-16 19:45:54 +00:00
rp = Rule_merge ( x [ i ] , rp ) ;
x [ i ] = 0 ;
}
x [ i ] = rp ;
rp = pNext ;
}
rp = 0 ;
for ( i = 0 ; i < sizeof ( x ) / sizeof ( x [ 0 ] ) ; i + + ) {
rp = Rule_merge ( x [ i ] , rp ) ;
}
return rp ;
}
2015-09-07 02:23:02 +00:00
/* forward reference */
static const char * minimum_size_type ( int lwr , int upr , int * pnByte ) ;
/* Print a single line of the "Parser Stats" output
*/
static void stats_line ( const char * zLabel , int iValue ) {
int nLabel = lemonStrlen ( zLabel ) ;
printf ( " %s%.*s %5d \n " , zLabel ,
35 - nLabel , " ................................ " ,
iValue ) ;
}
2000-05-29 14:26:00 +00:00
/* The main program. Parse the command line and do it... */
2020-09-16 16:55:56 +00:00
int main ( int argc , char * * argv ) {
2000-05-29 14:26:00 +00:00
static int version = 0 ;
static int rpflag = 0 ;
static int basisflag = 0 ;
static int compress = 0 ;
static int quiet = 0 ;
static int statistics = 0 ;
static int mhflag = 0 ;
2008-12-10 20:10:04 +00:00
static int nolinenosflag = 0 ;
2010-07-19 01:52:07 +00:00
static int noResort = 0 ;
2019-11-26 02:22:39 +00:00
static int sqlFlag = 0 ;
2020-07-03 15:41:08 +00:00
static int printPP = 0 ;
2018-04-20 20:47:49 +00:00
2000-05-29 14:26:00 +00:00
static struct s_options options [ ] = {
{ OPT_FLAG , " b " , ( char * ) & basisflag , " Print only the basis in report. " } ,
{ OPT_FLAG , " c " , ( char * ) & compress , " Don't compress the action table. " } ,
2018-04-20 20:47:49 +00:00
{ OPT_FSTR , " d " , ( char * ) & handle_d_option , " Output directory. Default '.' " } ,
2004-07-20 12:45:22 +00:00
{ OPT_FSTR , " D " , ( char * ) handle_D_option , " Define an %ifdef macro. " } ,
2020-07-03 15:41:08 +00:00
{ OPT_FLAG , " E " , ( char * ) & printPP , " Print input file after preprocessing. " } ,
2015-01-01 19:11:22 +00:00
{ OPT_FSTR , " f " , 0 , " Ignored. (Placeholder for -f compiler options.) " } ,
2000-05-29 14:26:00 +00:00
{ OPT_FLAG , " g " , ( char * ) & rpflag , " Print grammar without actions. " } ,
2015-01-01 19:11:22 +00:00
{ OPT_FSTR , " I " , 0 , " Ignored. (Placeholder for '-I' compiler options.) " } ,
2008-12-10 20:10:04 +00:00
{ OPT_FLAG , " m " , ( char * ) & mhflag , " Output a makeheaders compatible file. " } ,
{ OPT_FLAG , " l " , ( char * ) & nolinenosflag , " Do not print #line statements. " } ,
2015-01-01 19:11:22 +00:00
{ OPT_FSTR , " O " , 0 , " Ignored. (Placeholder for '-O' compiler options.) " } ,
2010-07-18 11:35:53 +00:00
{ OPT_FLAG , " p " , ( char * ) & showPrecedenceConflict ,
" Show conflicts resolved by precedence rules " } ,
2000-05-29 14:26:00 +00:00
{ OPT_FLAG , " q " , ( char * ) & quiet , " (Quiet) Don't print the report file. " } ,
2010-07-19 01:52:07 +00:00
{ OPT_FLAG , " r " , ( char * ) & noResort , " Do not sort or renumber states " } ,
2004-07-20 12:45:22 +00:00
{ OPT_FLAG , " s " , ( char * ) & statistics ,
" Print parser stats to standard output. " } ,
2019-11-26 02:22:39 +00:00
{ OPT_FLAG , " S " , ( char * ) & sqlFlag ,
" Generate the *.sql file describing the parser tables. " } ,
2000-05-29 14:26:00 +00:00
{ OPT_FLAG , " x " , ( char * ) & version , " Print the version number. " } ,
2015-01-01 19:11:22 +00:00
{ OPT_FSTR , " T " , ( char * ) handle_T_option , " Specify a template file. " } ,
{ OPT_FSTR , " W " , 0 , " Ignored. (Placeholder for '-W' compiler options.) " } ,
2000-05-29 14:26:00 +00:00
{ OPT_FLAG , 0 , 0 , 0 }
} ;
int i ;
2010-02-14 05:19:56 +00:00
int exitcode ;
2000-05-29 14:26:00 +00:00
struct lemon lem ;
2016-03-16 19:45:54 +00:00
struct rule * rp ;
2000-05-29 14:26:00 +00:00
2000-06-02 23:21:26 +00:00
OptInit ( argv , options , stderr ) ;
2000-05-29 14:26:00 +00:00
if ( version ) {
2001-09-16 00:13:26 +00:00
printf ( " Lemon version 1.0 \n " ) ;
2017-04-14 19:46:12 +00:00
exit ( 0 ) ;
2000-05-29 14:26:00 +00:00
}
2000-06-02 23:21:26 +00:00
if ( OptNArgs ( ) ! = 1 ) {
2000-05-29 14:26:00 +00:00
fprintf ( stderr , " Exactly one filename argument is required. \n " ) ;
exit ( 1 ) ;
}
2006-06-13 13:27:46 +00:00
memset ( & lem , 0 , sizeof ( lem ) ) ;
2000-05-29 14:26:00 +00:00
lem . errorcnt = 0 ;
/* Initialize the machine */
Strsafe_init ( ) ;
Symbol_init ( ) ;
State_init ( ) ;
2023-06-08 12:52:28 +00:00
lem . argv = argv ;
lem . argc = argc ;
2000-06-02 23:21:26 +00:00
lem . filename = OptArg ( 0 ) ;
2000-05-29 14:26:00 +00:00
lem . basisflag = basisflag ;
2008-12-10 20:10:04 +00:00
lem . nolinenosflag = nolinenosflag ;
2020-07-03 15:41:08 +00:00
lem . printPreprocessed = printPP ;
2000-05-29 14:26:00 +00:00
Symbol_new ( " $ " ) ;
/* Parse the input file */
Parse ( & lem ) ;
2020-07-03 15:41:08 +00:00
if ( lem . printPreprocessed | | lem . errorcnt ) exit ( lem . errorcnt ) ;
2006-06-13 13:27:46 +00:00
if ( lem . nrule = = 0 ) {
2000-05-29 14:26:00 +00:00
fprintf ( stderr , " Empty grammar. \n " ) ;
exit ( 1 ) ;
}
2018-04-16 14:31:34 +00:00
lem . errsym = Symbol_find ( " error " ) ;
2000-05-29 14:26:00 +00:00
/* Count and index the symbols of the grammar */
Symbol_new ( " {default} " ) ;
2014-01-11 03:06:18 +00:00
lem . nsymbol = Symbol_count ( ) ;
2000-05-29 14:26:00 +00:00
lem . symbols = Symbol_arrayof ( ) ;
2014-01-11 03:06:18 +00:00
for ( i = 0 ; i < lem . nsymbol ; i + + ) lem . symbols [ i ] - > index = i ;
qsort ( lem . symbols , lem . nsymbol , sizeof ( struct symbol * ) , Symbolcmpp ) ;
for ( i = 0 ; i < lem . nsymbol ; i + + ) lem . symbols [ i ] - > index = i ;
while ( lem . symbols [ i - 1 ] - > type = = MULTITERMINAL ) { i - - ; }
assert ( strcmp ( lem . symbols [ i - 1 ] - > name , " {default} " ) = = 0 ) ;
lem . nsymbol = i - 1 ;
2015-10-29 13:48:15 +00:00
for ( i = 1 ; ISUPPER ( lem . symbols [ i ] - > name [ 0 ] ) ; i + + ) ;
2000-05-29 14:26:00 +00:00
lem . nterminal = i ;
2016-05-23 14:24:31 +00:00
/* Assign sequential rule numbers. Start with 0. Put rules that have no
* * reduce action C - code associated with them last , so that the switch ( )
* * statement that selects reduction actions will have a smaller jump table .
*/
2016-03-16 19:45:54 +00:00
for ( i = 0 , rp = lem . rule ; rp ; rp = rp - > next ) {
rp - > iRule = rp - > code ? i + + : - 1 ;
}
2019-12-11 18:53:51 +00:00
lem . nruleWithAction = i ;
2016-03-16 19:45:54 +00:00
for ( rp = lem . rule ; rp ; rp = rp - > next ) {
if ( rp - > iRule < 0 ) rp - > iRule = i + + ;
}
lem . startRule = lem . rule ;
lem . rule = Rule_sort ( lem . rule ) ;
2000-05-29 14:26:00 +00:00
/* Generate a reprint of the grammar, if requested on the command line */
if ( rpflag ) {
Reprint ( & lem ) ;
} else {
/* Initialize the size for all follow and first sets */
2007-12-21 00:02:11 +00:00
SetSize ( lem . nterminal + 1 ) ;
2000-05-29 14:26:00 +00:00
/* Find the precedence for every production rule (that has one) */
FindRulePrecedences ( & lem ) ;
/* Compute the lambda-nonterminals and the first-sets for every
* * nonterminal */
FindFirstSets ( & lem ) ;
/* Compute all LR(0) states. Also record follow-set propagation
* * links so that the follow - set can be computed later */
lem . nstate = 0 ;
FindStates ( & lem ) ;
lem . sorted = State_arrayof ( ) ;
/* Tie up loose ends on the propagation links */
FindLinks ( & lem ) ;
/* Compute the follow set of every reducible configuration */
FindFollowSets ( & lem ) ;
/* Compute the action tables */
FindActions ( & lem ) ;
/* Compress the action tables */
if ( compress = = 0 ) CompressTables ( & lem ) ;
2005-11-05 15:03:59 +00:00
/* Reorder and renumber the states so that states with fewer choices
2010-07-19 01:52:07 +00:00
* * occur at the end . This is an optimization that helps make the
* * generated parser tables smaller . */
if ( noResort = = 0 ) ResortStates ( & lem ) ;
2005-11-05 15:03:59 +00:00
2000-05-29 14:26:00 +00:00
/* Generate a report of the parser generated. (the "y.output" file) */
if ( ! quiet ) ReportOutput ( & lem ) ;
/* Generate the source code for the parser */
2019-11-26 02:22:39 +00:00
ReportTable ( & lem , mhflag , sqlFlag ) ;
2000-05-29 14:26:00 +00:00
/* Produce a header file for use by the scanner. (This step is
* * omitted if the " -m " option is used because makeheaders will
* * generate the file for us . ) */
if ( ! mhflag ) ReportHeader ( & lem ) ;
}
if ( statistics ) {
2015-09-07 02:23:02 +00:00
printf ( " Parser statistics: \n " ) ;
stats_line ( " terminal symbols " , lem . nterminal ) ;
stats_line ( " non-terminal symbols " , lem . nsymbol - lem . nterminal ) ;
stats_line ( " total symbols " , lem . nsymbol ) ;
stats_line ( " rules " , lem . nrule ) ;
2015-09-07 18:23:37 +00:00
stats_line ( " states " , lem . nxstate ) ;
2015-09-07 02:23:02 +00:00
stats_line ( " conflicts " , lem . nconflict ) ;
stats_line ( " action table entries " , lem . nactiontab ) ;
2017-12-25 04:15:38 +00:00
stats_line ( " lookahead table entries " , lem . nlookaheadtab ) ;
2015-09-07 02:23:02 +00:00
stats_line ( " total table size (bytes) " , lem . tablesize ) ;
2000-05-29 14:26:00 +00:00
}
2010-02-16 16:09:03 +00:00
if ( lem . nconflict > 0 ) {
fprintf ( stderr , " %d parsing conflicts. \n " , lem . nconflict ) ;
2010-02-14 05:19:56 +00:00
}
/* return 0 on success, 1 on failure. */
2010-02-16 16:09:03 +00:00
exitcode = ( ( lem . errorcnt > 0 ) | | ( lem . nconflict > 0 ) ) ? 1 : 0 ;
2010-02-14 05:19:56 +00:00
exit ( exitcode ) ;
return ( exitcode ) ;
2000-05-29 14:26:00 +00:00
}
/******************** From the file "msort.c" *******************************/
/*
* * A generic merge - sort program .
* *
* * USAGE :
* * Let " ptr " be a pointer to some structure which is at the head of
* * a null - terminated list . Then to sort the list call :
* *
* * ptr = msort ( ptr , & ( ptr - > next ) , cmpfnc ) ;
* *
* * In the above , " cmpfnc " is a pointer to a function which compares
* * two instances of the structure and returns an integer , as in
* * strcmp . The second argument is a pointer to the pointer to the
* * second element of the linked list . This address is used to compute
* * the offset to the " next " field within the structure . The offset to
* * the " next " field must be constant for all structures in the list .
* *
* * The function returns a new pointer which is the head of the list
* * after sorting .
* *
* * ALGORITHM :
* * Merge - sort .
*/
/*
* * Return a pointer to the next structure in the linked list .
*/
2012-04-18 09:59:56 +00:00
# define NEXT(A) (*(char**)(((char*)A)+offset))
2000-05-29 14:26:00 +00:00
/*
* * Inputs :
* * a : A sorted , null - terminated linked list . ( May be null ) .
* * b : A sorted , null - terminated linked list . ( May be null ) .
* * cmp : A pointer to the comparison function .
* * offset : Offset in the structure to the " next " field .
* *
* * Return Value :
* * A pointer to the head of a sorted list containing the elements
* * of both a and b .
* *
* * Side effects :
* * The " next " pointers for elements in the lists a and b are
* * changed .
*/
2007-07-18 18:16:29 +00:00
static char * merge (
char * a ,
char * b ,
int ( * cmp ) ( const char * , const char * ) ,
int offset
) {
2000-05-29 14:26:00 +00:00
char * ptr , * head ;
if ( a = = 0 ) {
head = b ;
} else if ( b = = 0 ) {
head = a ;
} else {
2009-11-03 13:02:25 +00:00
if ( ( * cmp ) ( a , b ) < = 0 ) {
2000-05-29 14:26:00 +00:00
ptr = a ;
a = NEXT ( a ) ;
} else {
ptr = b ;
b = NEXT ( b ) ;
}
head = ptr ;
while ( a & & b ) {
2009-11-03 13:02:25 +00:00
if ( ( * cmp ) ( a , b ) < = 0 ) {
2000-05-29 14:26:00 +00:00
NEXT ( ptr ) = a ;
ptr = a ;
a = NEXT ( a ) ;
} else {
NEXT ( ptr ) = b ;
ptr = b ;
b = NEXT ( b ) ;
}
}
if ( a ) NEXT ( ptr ) = a ;
else NEXT ( ptr ) = b ;
}
return head ;
}
/*
* * Inputs :
* * list : Pointer to a singly - linked list of structures .
* * next : Pointer to pointer to the second element of the list .
* * cmp : A comparison function .
* *
* * Return Value :
* * A pointer to the head of a sorted list containing the elements
2021-01-07 16:10:14 +00:00
* * originally in list .
2000-05-29 14:26:00 +00:00
* *
* * Side effects :
* * The " next " pointers for elements in list are changed .
*/
# define LISTSIZE 30
2007-07-18 18:16:29 +00:00
static char * msort (
char * list ,
char * * next ,
int ( * cmp ) ( const char * , const char * )
) {
2001-10-25 20:37:16 +00:00
unsigned long offset ;
2000-05-29 14:26:00 +00:00
char * ep ;
char * set [ LISTSIZE ] ;
int i ;
2015-03-31 15:15:48 +00:00
offset = ( unsigned long ) ( ( char * ) next - ( char * ) list ) ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < LISTSIZE ; i + + ) set [ i ] = 0 ;
while ( list ) {
ep = list ;
list = NEXT ( list ) ;
NEXT ( ep ) = 0 ;
for ( i = 0 ; i < LISTSIZE - 1 & & set [ i ] ! = 0 ; i + + ) {
ep = merge ( ep , set [ i ] , cmp , offset ) ;
set [ i ] = 0 ;
}
set [ i ] = ep ;
}
ep = 0 ;
2009-11-03 13:02:25 +00:00
for ( i = 0 ; i < LISTSIZE ; i + + ) if ( set [ i ] ) ep = merge ( set [ i ] , ep , cmp , offset ) ;
2000-05-29 14:26:00 +00:00
return ep ;
}
/************************ From the file "option.c" **************************/
2019-05-10 16:16:19 +00:00
static char * * g_argv ;
2000-05-29 14:26:00 +00:00
static struct s_options * op ;
static FILE * errstream ;
# define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0)
/*
* * Print the command line with a carrot pointing to the k - th character
* * of the n - th field .
*/
2010-02-14 17:14:22 +00:00
static void errline ( int n , int k , FILE * err )
2000-05-29 14:26:00 +00:00
{
int spcnt , i ;
2021-10-04 16:14:51 +00:00
if ( g_argv [ 0 ] ) {
fprintf ( err , " %s " , g_argv [ 0 ] ) ;
spcnt = lemonStrlen ( g_argv [ 0 ] ) + 1 ;
} else {
spcnt = 0 ;
}
2019-05-10 16:16:19 +00:00
for ( i = 1 ; i < n & & g_argv [ i ] ; i + + ) {
fprintf ( err , " %s " , g_argv [ i ] ) ;
spcnt + = lemonStrlen ( g_argv [ i ] ) + 1 ;
2000-05-29 14:26:00 +00:00
}
spcnt + = k ;
2019-05-10 16:16:19 +00:00
for ( ; g_argv [ i ] ; i + + ) fprintf ( err , " %s " , g_argv [ i ] ) ;
2000-05-29 14:26:00 +00:00
if ( spcnt < 20 ) {
fprintf ( err , " \n %*s^-- here \n " , spcnt , " " ) ;
} else {
fprintf ( err , " \n %*shere --^ \n " , spcnt - 7 , " " ) ;
}
}
/*
* * Return the index of the N - th non - switch argument . Return - 1
* * if N is out of range .
*/
2010-02-14 17:14:22 +00:00
static int argindex ( int n )
2000-05-29 14:26:00 +00:00
{
int i ;
int dashdash = 0 ;
2019-05-10 16:16:19 +00:00
if ( g_argv ! = 0 & & * g_argv ! = 0 ) {
for ( i = 1 ; g_argv [ i ] ; i + + ) {
if ( dashdash | | ! ISOPT ( g_argv [ i ] ) ) {
2000-05-29 14:26:00 +00:00
if ( n = = 0 ) return i ;
n - - ;
}
2019-05-10 16:16:19 +00:00
if ( strcmp ( g_argv [ i ] , " -- " ) = = 0 ) dashdash = 1 ;
2000-05-29 14:26:00 +00:00
}
}
return - 1 ;
}
static char emsg [ ] = " Command line syntax error: " ;
/*
* * Process a flag command line argument .
*/
2010-02-14 17:14:22 +00:00
static int handleflags ( int i , FILE * err )
2000-05-29 14:26:00 +00:00
{
int v ;
int errcnt = 0 ;
int j ;
for ( j = 0 ; op [ j ] . label ; j + + ) {
2019-05-10 16:16:19 +00:00
if ( strncmp ( & g_argv [ i ] [ 1 ] , op [ j ] . label , lemonStrlen ( op [ j ] . label ) ) = = 0 ) break ;
2000-05-29 14:26:00 +00:00
}
2019-05-10 16:16:19 +00:00
v = g_argv [ i ] [ 0 ] = = ' - ' ? 1 : 0 ;
2000-05-29 14:26:00 +00:00
if ( op [ j ] . label = = 0 ) {
if ( err ) {
fprintf ( err , " %sundefined option. \n " , emsg ) ;
errline ( i , 1 , err ) ;
}
errcnt + + ;
2015-01-01 19:11:22 +00:00
} else if ( op [ j ] . arg = = 0 ) {
/* Ignore this option */
2000-05-29 14:26:00 +00:00
} else if ( op [ j ] . type = = OPT_FLAG ) {
* ( ( int * ) op [ j ] . arg ) = v ;
} else if ( op [ j ] . type = = OPT_FFLAG ) {
2010-02-14 17:14:22 +00:00
( * ( void ( * ) ( int ) ) ( op [ j ] . arg ) ) ( v ) ;
2004-07-20 12:45:22 +00:00
} else if ( op [ j ] . type = = OPT_FSTR ) {
2019-05-10 16:16:19 +00:00
( * ( void ( * ) ( char * ) ) ( op [ j ] . arg ) ) ( & g_argv [ i ] [ 2 ] ) ;
2000-05-29 14:26:00 +00:00
} else {
if ( err ) {
fprintf ( err , " %smissing argument on switch. \n " , emsg ) ;
errline ( i , 1 , err ) ;
}
errcnt + + ;
}
return errcnt ;
}
/*
* * Process a command line switch which has an argument .
*/
2010-02-14 17:14:22 +00:00
static int handleswitch ( int i , FILE * err )
2000-05-29 14:26:00 +00:00
{
int lv = 0 ;
double dv = 0.0 ;
char * sv = 0 , * end ;
char * cp ;
int j ;
int errcnt = 0 ;
2019-05-10 16:16:19 +00:00
cp = strchr ( g_argv [ i ] , ' = ' ) ;
2006-03-06 20:55:46 +00:00
assert ( cp ! = 0 ) ;
2000-05-29 14:26:00 +00:00
* cp = 0 ;
for ( j = 0 ; op [ j ] . label ; j + + ) {
2019-05-10 16:16:19 +00:00
if ( strcmp ( g_argv [ i ] , op [ j ] . label ) = = 0 ) break ;
2000-05-29 14:26:00 +00:00
}
* cp = ' = ' ;
if ( op [ j ] . label = = 0 ) {
if ( err ) {
fprintf ( err , " %sundefined option. \n " , emsg ) ;
errline ( i , 0 , err ) ;
}
errcnt + + ;
} else {
cp + + ;
switch ( op [ j ] . type ) {
case OPT_FLAG :
case OPT_FFLAG :
if ( err ) {
fprintf ( err , " %soption requires an argument. \n " , emsg ) ;
errline ( i , 0 , err ) ;
}
errcnt + + ;
break ;
case OPT_DBL :
case OPT_FDBL :
dv = strtod ( cp , & end ) ;
if ( * end ) {
if ( err ) {
2015-09-04 18:03:45 +00:00
fprintf ( err ,
" %sillegal character in floating-point argument. \n " , emsg ) ;
2019-05-10 16:16:19 +00:00
errline ( i , ( int ) ( ( char * ) end - ( char * ) g_argv [ i ] ) , err ) ;
2000-05-29 14:26:00 +00:00
}
errcnt + + ;
}
break ;
case OPT_INT :
case OPT_FINT :
lv = strtol ( cp , & end , 0 ) ;
if ( * end ) {
if ( err ) {
fprintf ( err , " %sillegal character in integer argument. \n " , emsg ) ;
2019-05-10 16:16:19 +00:00
errline ( i , ( int ) ( ( char * ) end - ( char * ) g_argv [ i ] ) , err ) ;
2000-05-29 14:26:00 +00:00
}
errcnt + + ;
}
break ;
case OPT_STR :
case OPT_FSTR :
sv = cp ;
break ;
}
switch ( op [ j ] . type ) {
case OPT_FLAG :
case OPT_FFLAG :
break ;
case OPT_DBL :
* ( double * ) ( op [ j ] . arg ) = dv ;
break ;
case OPT_FDBL :
2010-02-14 17:14:22 +00:00
( * ( void ( * ) ( double ) ) ( op [ j ] . arg ) ) ( dv ) ;
2000-05-29 14:26:00 +00:00
break ;
case OPT_INT :
* ( int * ) ( op [ j ] . arg ) = lv ;
break ;
case OPT_FINT :
2010-02-14 17:14:22 +00:00
( * ( void ( * ) ( int ) ) ( op [ j ] . arg ) ) ( ( int ) lv ) ;
2000-05-29 14:26:00 +00:00
break ;
case OPT_STR :
* ( char * * ) ( op [ j ] . arg ) = sv ;
break ;
case OPT_FSTR :
2010-02-14 17:14:22 +00:00
( * ( void ( * ) ( char * ) ) ( op [ j ] . arg ) ) ( sv ) ;
2000-05-29 14:26:00 +00:00
break ;
}
}
return errcnt ;
}
2010-02-14 17:14:22 +00:00
int OptInit ( char * * a , struct s_options * o , FILE * err )
2000-05-29 14:26:00 +00:00
{
int errcnt = 0 ;
2019-05-10 16:16:19 +00:00
g_argv = a ;
2000-05-29 14:26:00 +00:00
op = o ;
errstream = err ;
2019-05-10 16:16:19 +00:00
if ( g_argv & & * g_argv & & op ) {
2000-05-29 14:26:00 +00:00
int i ;
2019-05-10 16:16:19 +00:00
for ( i = 1 ; g_argv [ i ] ; i + + ) {
if ( g_argv [ i ] [ 0 ] = = ' + ' | | g_argv [ i ] [ 0 ] = = ' - ' ) {
2000-05-29 14:26:00 +00:00
errcnt + = handleflags ( i , err ) ;
2019-05-10 16:16:19 +00:00
} else if ( strchr ( g_argv [ i ] , ' = ' ) ) {
2000-05-29 14:26:00 +00:00
errcnt + = handleswitch ( i , err ) ;
}
}
}
if ( errcnt > 0 ) {
fprintf ( err , " Valid command line options for \" %s \" are: \n " , * a ) ;
2000-06-02 23:21:26 +00:00
OptPrint ( ) ;
2000-05-29 14:26:00 +00:00
exit ( 1 ) ;
}
return 0 ;
}
2017-04-14 19:44:15 +00:00
int OptNArgs ( void ) {
2000-05-29 14:26:00 +00:00
int cnt = 0 ;
int dashdash = 0 ;
int i ;
2019-05-10 16:16:19 +00:00
if ( g_argv ! = 0 & & g_argv [ 0 ] ! = 0 ) {
for ( i = 1 ; g_argv [ i ] ; i + + ) {
if ( dashdash | | ! ISOPT ( g_argv [ i ] ) ) cnt + + ;
if ( strcmp ( g_argv [ i ] , " -- " ) = = 0 ) dashdash = 1 ;
2000-05-29 14:26:00 +00:00
}
}
return cnt ;
}
2010-02-14 17:14:22 +00:00
char * OptArg ( int n )
2000-05-29 14:26:00 +00:00
{
int i ;
i = argindex ( n ) ;
2019-05-10 16:16:19 +00:00
return i > = 0 ? g_argv [ i ] : 0 ;
2000-05-29 14:26:00 +00:00
}
2010-02-14 17:14:22 +00:00
void OptErr ( int n )
2000-05-29 14:26:00 +00:00
{
int i ;
i = argindex ( n ) ;
if ( i > = 0 ) errline ( i , 0 , errstream ) ;
}
2017-04-14 19:44:15 +00:00
void OptPrint ( void ) {
2000-05-29 14:26:00 +00:00
int i ;
int max , len ;
max = 0 ;
for ( i = 0 ; op [ i ] . label ; i + + ) {
2008-08-13 20:09:06 +00:00
len = lemonStrlen ( op [ i ] . label ) + 1 ;
2000-05-29 14:26:00 +00:00
switch ( op [ i ] . type ) {
case OPT_FLAG :
case OPT_FFLAG :
break ;
case OPT_INT :
case OPT_FINT :
len + = 9 ; /* length of "<integer>" */
break ;
case OPT_DBL :
case OPT_FDBL :
len + = 6 ; /* length of "<real>" */
break ;
case OPT_STR :
case OPT_FSTR :
len + = 8 ; /* length of "<string>" */
break ;
}
if ( len > max ) max = len ;
}
for ( i = 0 ; op [ i ] . label ; i + + ) {
switch ( op [ i ] . type ) {
case OPT_FLAG :
case OPT_FFLAG :
fprintf ( errstream , " -%-*s %s \n " , max , op [ i ] . label , op [ i ] . message ) ;
break ;
case OPT_INT :
case OPT_FINT :
2015-01-01 19:11:22 +00:00
fprintf ( errstream , " -%s<integer>%*s %s \n " , op [ i ] . label ,
2008-08-13 20:09:06 +00:00
( int ) ( max - lemonStrlen ( op [ i ] . label ) - 9 ) , " " , op [ i ] . message ) ;
2000-05-29 14:26:00 +00:00
break ;
case OPT_DBL :
case OPT_FDBL :
2015-01-01 19:11:22 +00:00
fprintf ( errstream , " -%s<real>%*s %s \n " , op [ i ] . label ,
2008-08-13 20:09:06 +00:00
( int ) ( max - lemonStrlen ( op [ i ] . label ) - 6 ) , " " , op [ i ] . message ) ;
2000-05-29 14:26:00 +00:00
break ;
case OPT_STR :
case OPT_FSTR :
2015-01-01 19:11:22 +00:00
fprintf ( errstream , " -%s<string>%*s %s \n " , op [ i ] . label ,
2008-08-13 20:09:06 +00:00
( int ) ( max - lemonStrlen ( op [ i ] . label ) - 8 ) , " " , op [ i ] . message ) ;
2000-05-29 14:26:00 +00:00
break ;
}
}
}
/*********************** From the file "parse.c" ****************************/
/*
* * Input file parser for the LEMON parser generator .
*/
/* The state of the parser */
2010-02-14 17:14:22 +00:00
enum e_state {
INITIALIZE ,
WAITING_FOR_DECL_OR_RULE ,
WAITING_FOR_DECL_KEYWORD ,
WAITING_FOR_DECL_ARG ,
WAITING_FOR_PRECEDENCE_SYMBOL ,
WAITING_FOR_ARROW ,
IN_RHS ,
LHS_ALIAS_1 ,
LHS_ALIAS_2 ,
LHS_ALIAS_3 ,
RHS_ALIAS_1 ,
RHS_ALIAS_2 ,
PRECEDENCE_MARK_1 ,
PRECEDENCE_MARK_2 ,
RESYNC_AFTER_RULE_ERROR ,
RESYNC_AFTER_DECL_ERROR ,
WAITING_FOR_DESTRUCTOR_SYMBOL ,
WAITING_FOR_DATATYPE_SYMBOL ,
WAITING_FOR_FALLBACK_ID ,
2014-01-11 03:06:18 +00:00
WAITING_FOR_WILDCARD_ID ,
WAITING_FOR_CLASS_ID ,
2017-08-02 03:21:11 +00:00
WAITING_FOR_CLASS_TOKEN ,
WAITING_FOR_TOKEN_NAME
2010-02-14 17:14:22 +00:00
} ;
2000-05-29 14:26:00 +00:00
struct pstate {
char * filename ; /* Name of the input file */
int tokenlineno ; /* Linenumber at which current token starts */
int errorcnt ; /* Number of errors so far */
char * tokenstart ; /* Text of current token */
struct lemon * gp ; /* Global state vector */
2010-02-14 17:14:22 +00:00
enum e_state state ; /* The state of the parser */
2002-06-06 18:54:39 +00:00
struct symbol * fallback ; /* The fallback token */
2014-01-11 03:06:18 +00:00
struct symbol * tkclass ; /* Token class symbol */
2000-05-29 14:26:00 +00:00
struct symbol * lhs ; /* Left-hand side of current rule */
2010-02-14 17:14:22 +00:00
const char * lhsalias ; /* Alias for the LHS */
2000-05-29 14:26:00 +00:00
int nrhs ; /* Number of right-hand side symbols seen */
struct symbol * rhs [ MAXRHS ] ; /* RHS symbols */
2010-02-14 17:14:22 +00:00
const char * alias [ MAXRHS ] ; /* Aliases for each RHS symbol (or NULL) */
2000-05-29 14:26:00 +00:00
struct rule * prevrule ; /* Previous rule parsed */
2010-02-14 17:14:22 +00:00
const char * declkeyword ; /* Keyword of a declaration */
2000-05-29 14:26:00 +00:00
char * * declargslot ; /* Where the declaration argument should be put */
2008-04-27 22:19:44 +00:00
int insertLineMacro ; /* Add #line before declaration insert */
2008-07-01 17:13:57 +00:00
int * decllinenoslot ; /* Where to write declaration line number */
2000-05-29 14:26:00 +00:00
enum e_assoc declassoc ; /* Assign this association to decl arguments */
int preccounter ; /* Assign this precedence to decl arguments */
struct rule * firstrule ; /* Pointer to first rule in the grammar */
struct rule * lastrule ; /* Pointer to the most recently parsed rule */
} ;
/* Parse a single token */
2010-02-14 17:14:22 +00:00
static void parseonetoken ( struct pstate * psp )
2000-05-29 14:26:00 +00:00
{
2010-02-14 17:14:22 +00:00
const char * x ;
2000-05-29 14:26:00 +00:00
x = Strsafe ( psp - > tokenstart ) ; /* Save the token permanently */
#if 0
printf ( " %s:%d: Token=[%s] state=%d \n " , psp - > filename , psp - > tokenlineno ,
x , psp - > state ) ;
# endif
switch ( psp - > state ) {
case INITIALIZE :
psp - > prevrule = 0 ;
psp - > preccounter = 0 ;
psp - > firstrule = psp - > lastrule = 0 ;
psp - > gp - > nrule = 0 ;
2020-09-16 16:55:56 +00:00
/* fall through */
2000-05-29 14:26:00 +00:00
case WAITING_FOR_DECL_OR_RULE :
if ( x [ 0 ] = = ' % ' ) {
psp - > state = WAITING_FOR_DECL_KEYWORD ;
2015-10-29 13:48:15 +00:00
} else if ( ISLOWER ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
psp - > lhs = Symbol_new ( x ) ;
psp - > nrhs = 0 ;
psp - > lhsalias = 0 ;
psp - > state = WAITING_FOR_ARROW ;
} else if ( x [ 0 ] = = ' { ' ) {
if ( psp - > prevrule = = 0 ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
2019-12-12 00:20:40 +00:00
" There is no prior rule upon which to attach the code "
" fragment which begins on this line. " ) ;
2000-05-29 14:26:00 +00:00
psp - > errorcnt + + ;
2012-08-20 15:53:54 +00:00
} else if ( psp - > prevrule - > code ! = 0 ) {
2000-05-29 14:26:00 +00:00
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
2019-12-12 00:20:40 +00:00
" Code fragment beginning on this line is not the first "
" to follow the previous rule. " ) ;
2000-05-29 14:26:00 +00:00
psp - > errorcnt + + ;
2019-12-10 20:41:48 +00:00
} else if ( strcmp ( x , " {NEVER-REDUCE " ) = = 0 ) {
psp - > prevrule - > neverReduce = 1 ;
2000-05-29 14:26:00 +00:00
} else {
psp - > prevrule - > line = psp - > tokenlineno ;
psp - > prevrule - > code = & x [ 1 ] ;
2016-05-23 14:24:31 +00:00
psp - > prevrule - > noCode = 0 ;
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
} else if ( x [ 0 ] = = ' [ ' ) {
psp - > state = PRECEDENCE_MARK_1 ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Token \" %s \" should be either \" %% \" or a nonterminal name. " ,
x ) ;
psp - > errorcnt + + ;
}
break ;
case PRECEDENCE_MARK_1 :
2015-10-29 13:48:15 +00:00
if ( ! ISUPPER ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" The precedence symbol must be a terminal. " ) ;
psp - > errorcnt + + ;
} else if ( psp - > prevrule = = 0 ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" There is no prior rule to assign precedence \" [%s] \" . " , x ) ;
psp - > errorcnt + + ;
} else if ( psp - > prevrule - > precsym ! = 0 ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
2019-12-12 00:20:40 +00:00
" Precedence mark on this line is not the first "
" to follow the previous rule. " ) ;
2000-05-29 14:26:00 +00:00
psp - > errorcnt + + ;
} else {
psp - > prevrule - > precsym = Symbol_new ( x ) ;
}
psp - > state = PRECEDENCE_MARK_2 ;
break ;
case PRECEDENCE_MARK_2 :
if ( x [ 0 ] ! = ' ] ' ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Missing \" ] \" on precedence mark. " ) ;
psp - > errorcnt + + ;
}
psp - > state = WAITING_FOR_DECL_OR_RULE ;
break ;
case WAITING_FOR_ARROW :
if ( x [ 0 ] = = ' : ' & & x [ 1 ] = = ' : ' & & x [ 2 ] = = ' = ' ) {
psp - > state = IN_RHS ;
} else if ( x [ 0 ] = = ' ( ' ) {
psp - > state = LHS_ALIAS_1 ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Expected to see a \" : \" following the LHS symbol \" %s \" . " ,
psp - > lhs - > name ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_RULE_ERROR ;
}
break ;
case LHS_ALIAS_1 :
2015-10-29 13:48:15 +00:00
if ( ISALPHA ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
psp - > lhsalias = x ;
psp - > state = LHS_ALIAS_2 ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" \" %s \" is not a valid alias for the LHS \" %s \" \n " ,
x , psp - > lhs - > name ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_RULE_ERROR ;
}
break ;
case LHS_ALIAS_2 :
if ( x [ 0 ] = = ' ) ' ) {
psp - > state = LHS_ALIAS_3 ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Missing \" ) \" following LHS alias name \" %s \" . " , psp - > lhsalias ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_RULE_ERROR ;
}
break ;
case LHS_ALIAS_3 :
if ( x [ 0 ] = = ' : ' & & x [ 1 ] = = ' : ' & & x [ 2 ] = = ' = ' ) {
psp - > state = IN_RHS ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Missing \" -> \" following: \" %s(%s) \" . " ,
psp - > lhs - > name , psp - > lhsalias ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_RULE_ERROR ;
}
break ;
case IN_RHS :
if ( x [ 0 ] = = ' . ' ) {
struct rule * rp ;
2017-04-14 19:46:12 +00:00
rp = ( struct rule * ) calloc ( sizeof ( struct rule ) +
2007-12-21 00:02:11 +00:00
sizeof ( struct symbol * ) * psp - > nrhs + sizeof ( char * ) * psp - > nrhs , 1 ) ;
2000-05-29 14:26:00 +00:00
if ( rp = = 0 ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Can't allocate enough memory for this rule. " ) ;
psp - > errorcnt + + ;
psp - > prevrule = 0 ;
2012-08-20 15:53:54 +00:00
} else {
2000-05-29 14:26:00 +00:00
int i ;
rp - > ruleline = psp - > tokenlineno ;
rp - > rhs = ( struct symbol * * ) & rp [ 1 ] ;
2010-02-14 17:14:22 +00:00
rp - > rhsalias = ( const char * * ) & ( rp - > rhs [ psp - > nrhs ] ) ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < psp - > nrhs ; i + + ) {
rp - > rhs [ i ] = psp - > rhs [ i ] ;
rp - > rhsalias [ i ] = psp - > alias [ i ] ;
2018-04-21 20:24:19 +00:00
if ( rp - > rhsalias [ i ] ! = 0 ) { rp - > rhs [ i ] - > bContent = 1 ; }
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
rp - > lhs = psp - > lhs ;
rp - > lhsalias = psp - > lhsalias ;
rp - > nrhs = psp - > nrhs ;
rp - > code = 0 ;
2016-05-23 14:24:31 +00:00
rp - > noCode = 1 ;
2000-05-29 14:26:00 +00:00
rp - > precsym = 0 ;
rp - > index = psp - > gp - > nrule + + ;
rp - > nextlhs = rp - > lhs - > rule ;
rp - > lhs - > rule = rp ;
rp - > next = 0 ;
if ( psp - > firstrule = = 0 ) {
psp - > firstrule = psp - > lastrule = rp ;
2012-08-20 15:53:54 +00:00
} else {
2000-05-29 14:26:00 +00:00
psp - > lastrule - > next = rp ;
psp - > lastrule = rp ;
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
psp - > prevrule = rp ;
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
psp - > state = WAITING_FOR_DECL_OR_RULE ;
2015-10-29 13:48:15 +00:00
} else if ( ISALPHA ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
if ( psp - > nrhs > = MAXRHS ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
2008-01-22 01:48:05 +00:00
" Too many symbols on RHS of rule beginning at \" %s \" . " ,
2000-05-29 14:26:00 +00:00
x ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_RULE_ERROR ;
2012-08-20 15:53:54 +00:00
} else {
2000-05-29 14:26:00 +00:00
psp - > rhs [ psp - > nrhs ] = Symbol_new ( x ) ;
psp - > alias [ psp - > nrhs ] = 0 ;
psp - > nrhs + + ;
2012-08-20 15:53:54 +00:00
}
2020-09-05 06:21:54 +00:00
} else if ( ( x [ 0 ] = = ' | ' | | x [ 0 ] = = ' / ' ) & & psp - > nrhs > 0 & & ISUPPER ( x [ 1 ] ) ) {
2005-11-06 04:06:59 +00:00
struct symbol * msp = psp - > rhs [ psp - > nrhs - 1 ] ;
if ( msp - > type ! = MULTITERMINAL ) {
struct symbol * origsp = msp ;
2010-02-14 17:14:22 +00:00
msp = ( struct symbol * ) calloc ( 1 , sizeof ( * msp ) ) ;
2005-11-06 04:06:59 +00:00
memset ( msp , 0 , sizeof ( * msp ) ) ;
msp - > type = MULTITERMINAL ;
msp - > nsubsym = 1 ;
2010-02-14 17:14:22 +00:00
msp - > subsym = ( struct symbol * * ) calloc ( 1 , sizeof ( struct symbol * ) ) ;
2005-11-06 04:06:59 +00:00
msp - > subsym [ 0 ] = origsp ;
msp - > name = origsp - > name ;
psp - > rhs [ psp - > nrhs - 1 ] = msp ;
}
msp - > nsubsym + + ;
2010-02-14 17:14:22 +00:00
msp - > subsym = ( struct symbol * * ) realloc ( msp - > subsym ,
sizeof ( struct symbol * ) * msp - > nsubsym ) ;
2005-11-06 04:06:59 +00:00
msp - > subsym [ msp - > nsubsym - 1 ] = Symbol_new ( & x [ 1 ] ) ;
2015-10-29 13:48:15 +00:00
if ( ISLOWER ( x [ 1 ] ) | | ISLOWER ( msp - > subsym [ 0 ] - > name [ 0 ] ) ) {
2005-11-06 04:06:59 +00:00
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Cannot form a compound containing a non-terminal " ) ;
psp - > errorcnt + + ;
}
2000-05-29 14:26:00 +00:00
} else if ( x [ 0 ] = = ' ( ' & & psp - > nrhs > 0 ) {
psp - > state = RHS_ALIAS_1 ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Illegal character on RHS of rule: \" %s \" . " , x ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_RULE_ERROR ;
}
break ;
case RHS_ALIAS_1 :
2015-10-29 13:48:15 +00:00
if ( ISALPHA ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
psp - > alias [ psp - > nrhs - 1 ] = x ;
psp - > state = RHS_ALIAS_2 ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" \" %s \" is not a valid alias for the RHS symbol \" %s \" \n " ,
x , psp - > rhs [ psp - > nrhs - 1 ] - > name ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_RULE_ERROR ;
}
break ;
case RHS_ALIAS_2 :
if ( x [ 0 ] = = ' ) ' ) {
psp - > state = IN_RHS ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Missing \" ) \" following LHS alias name \" %s \" . " , psp - > lhsalias ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_RULE_ERROR ;
}
break ;
case WAITING_FOR_DECL_KEYWORD :
2015-10-29 13:48:15 +00:00
if ( ISALPHA ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
psp - > declkeyword = x ;
psp - > declargslot = 0 ;
2008-07-01 17:13:57 +00:00
psp - > decllinenoslot = 0 ;
2008-04-27 22:19:44 +00:00
psp - > insertLineMacro = 1 ;
2000-05-29 14:26:00 +00:00
psp - > state = WAITING_FOR_DECL_ARG ;
if ( strcmp ( x , " name " ) = = 0 ) {
psp - > declargslot = & ( psp - > gp - > name ) ;
2008-04-27 22:19:44 +00:00
psp - > insertLineMacro = 0 ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " include " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > declargslot = & ( psp - > gp - > include ) ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " code " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > declargslot = & ( psp - > gp - > extracode ) ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " token_destructor " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > declargslot = & psp - > gp - > tokendest ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " default_destructor " ) = = 0 ) {
2001-04-03 16:53:21 +00:00
psp - > declargslot = & psp - > gp - > vardest ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " token_prefix " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > declargslot = & psp - > gp - > tokenprefix ;
2008-04-27 22:19:44 +00:00
psp - > insertLineMacro = 0 ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " syntax_error " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > declargslot = & ( psp - > gp - > error ) ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " parse_accept " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > declargslot = & ( psp - > gp - > accept ) ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " parse_failure " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > declargslot = & ( psp - > gp - > failure ) ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " stack_overflow " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > declargslot = & ( psp - > gp - > overflow ) ;
} else if ( strcmp ( x , " extra_argument " ) = = 0 ) {
psp - > declargslot = & ( psp - > gp - > arg ) ;
2008-04-27 22:19:44 +00:00
psp - > insertLineMacro = 0 ;
2018-04-21 13:51:42 +00:00
} else if ( strcmp ( x , " extra_context " ) = = 0 ) {
psp - > declargslot = & ( psp - > gp - > ctx ) ;
psp - > insertLineMacro = 0 ;
2000-05-29 14:26:00 +00:00
} else if ( strcmp ( x , " token_type " ) = = 0 ) {
psp - > declargslot = & ( psp - > gp - > tokentype ) ;
2008-04-27 22:19:44 +00:00
psp - > insertLineMacro = 0 ;
2001-04-03 16:53:21 +00:00
} else if ( strcmp ( x , " default_type " ) = = 0 ) {
psp - > declargslot = & ( psp - > gp - > vartype ) ;
2008-04-27 22:19:44 +00:00
psp - > insertLineMacro = 0 ;
2000-05-29 14:26:00 +00:00
} else if ( strcmp ( x , " stack_size " ) = = 0 ) {
psp - > declargslot = & ( psp - > gp - > stacksize ) ;
2008-04-27 22:19:44 +00:00
psp - > insertLineMacro = 0 ;
2000-05-29 14:26:00 +00:00
} else if ( strcmp ( x , " start_symbol " ) = = 0 ) {
psp - > declargslot = & ( psp - > gp - > start ) ;
2008-04-27 22:19:44 +00:00
psp - > insertLineMacro = 0 ;
2000-05-29 14:26:00 +00:00
} else if ( strcmp ( x , " left " ) = = 0 ) {
psp - > preccounter + + ;
psp - > declassoc = LEFT ;
psp - > state = WAITING_FOR_PRECEDENCE_SYMBOL ;
} else if ( strcmp ( x , " right " ) = = 0 ) {
psp - > preccounter + + ;
psp - > declassoc = RIGHT ;
psp - > state = WAITING_FOR_PRECEDENCE_SYMBOL ;
} else if ( strcmp ( x , " nonassoc " ) = = 0 ) {
psp - > preccounter + + ;
psp - > declassoc = NONE ;
psp - > state = WAITING_FOR_PRECEDENCE_SYMBOL ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " destructor " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > state = WAITING_FOR_DESTRUCTOR_SYMBOL ;
2012-08-20 15:53:54 +00:00
} else if ( strcmp ( x , " type " ) = = 0 ) {
2000-05-29 14:26:00 +00:00
psp - > state = WAITING_FOR_DATATYPE_SYMBOL ;
2002-06-06 18:54:39 +00:00
} else if ( strcmp ( x , " fallback " ) = = 0 ) {
psp - > fallback = 0 ;
psp - > state = WAITING_FOR_FALLBACK_ID ;
2017-08-02 03:21:11 +00:00
} else if ( strcmp ( x , " token " ) = = 0 ) {
psp - > state = WAITING_FOR_TOKEN_NAME ;
2006-06-10 13:29:31 +00:00
} else if ( strcmp ( x , " wildcard " ) = = 0 ) {
psp - > state = WAITING_FOR_WILDCARD_ID ;
2014-01-11 03:06:18 +00:00
} else if ( strcmp ( x , " token_class " ) = = 0 ) {
psp - > state = WAITING_FOR_CLASS_ID ;
2000-05-29 14:26:00 +00:00
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Unknown declaration keyword: \" %%%s \" . " , x ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Illegal declaration keyword: \" %s \" . " , x ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
}
break ;
case WAITING_FOR_DESTRUCTOR_SYMBOL :
2015-10-29 13:48:15 +00:00
if ( ! ISALPHA ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
2010-02-17 20:22:10 +00:00
" Symbol name missing after %%destructor keyword " ) ;
2000-05-29 14:26:00 +00:00
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
} else {
2010-03-03 17:06:32 +00:00
struct symbol * sp = Symbol_new ( x ) ;
psp - > declargslot = & sp - > destructor ;
psp - > decllinenoslot = & sp - > destLineno ;
psp - > insertLineMacro = 1 ;
psp - > state = WAITING_FOR_DECL_ARG ;
2000-05-29 14:26:00 +00:00
}
break ;
case WAITING_FOR_DATATYPE_SYMBOL :
2015-10-29 13:48:15 +00:00
if ( ! ISALPHA ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
2010-02-17 20:22:10 +00:00
" Symbol name missing after %%type keyword " ) ;
2000-05-29 14:26:00 +00:00
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
} else {
2010-02-17 20:31:32 +00:00
struct symbol * sp = Symbol_find ( x ) ;
if ( ( sp ) & & ( sp - > datatype ) ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Symbol %%type \" %s \" already defined " , x ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
} else {
if ( ! sp ) {
sp = Symbol_new ( x ) ;
}
psp - > declargslot = & sp - > datatype ;
psp - > insertLineMacro = 0 ;
psp - > state = WAITING_FOR_DECL_ARG ;
}
2000-05-29 14:26:00 +00:00
}
break ;
case WAITING_FOR_PRECEDENCE_SYMBOL :
if ( x [ 0 ] = = ' . ' ) {
psp - > state = WAITING_FOR_DECL_OR_RULE ;
2015-10-29 13:48:15 +00:00
} else if ( ISUPPER ( x [ 0 ] ) ) {
2000-05-29 14:26:00 +00:00
struct symbol * sp ;
sp = Symbol_new ( x ) ;
if ( sp - > prec > = 0 ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Symbol \" %s \" has already be given a precedence. " , x ) ;
psp - > errorcnt + + ;
2012-08-20 15:53:54 +00:00
} else {
2000-05-29 14:26:00 +00:00
sp - > prec = psp - > preccounter ;
sp - > assoc = psp - > declassoc ;
2012-08-20 15:53:54 +00:00
}
2000-05-29 14:26:00 +00:00
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Can't assign a precedence to \" %s \" . " , x ) ;
psp - > errorcnt + + ;
}
break ;
case WAITING_FOR_DECL_ARG :
2015-10-29 13:48:15 +00:00
if ( x [ 0 ] = = ' { ' | | x [ 0 ] = = ' \" ' | | ISALNUM ( x [ 0 ] ) ) {
2010-02-14 17:14:22 +00:00
const char * zOld , * zNew ;
char * zBuf , * z ;
2015-01-12 18:02:52 +00:00
int nOld , n , nLine = 0 , nNew , nBack ;
2008-07-14 12:21:08 +00:00
int addLineMacro ;
2008-04-27 22:19:44 +00:00
char zLine [ 50 ] ;
zNew = x ;
if ( zNew [ 0 ] = = ' " ' | | zNew [ 0 ] = = ' { ' ) zNew + + ;
2008-08-13 20:09:06 +00:00
nNew = lemonStrlen ( zNew ) ;
2008-04-27 22:19:44 +00:00
if ( * psp - > declargslot ) {
zOld = * psp - > declargslot ;
} else {
zOld = " " ;
}
2008-08-13 20:09:06 +00:00
nOld = lemonStrlen ( zOld ) ;
2008-04-27 22:19:44 +00:00
n = nOld + nNew + 20 ;
2020-09-01 11:20:03 +00:00
addLineMacro = ! psp - > gp - > nolinenosflag
& & psp - > insertLineMacro
& & psp - > tokenlineno > 1
& & ( psp - > decllinenoslot = = 0 | | psp - > decllinenoslot [ 0 ] ! = 0 ) ;
2008-07-14 12:21:08 +00:00
if ( addLineMacro ) {
2008-04-27 22:19:44 +00:00
for ( z = psp - > filename , nBack = 0 ; * z ; z + + ) {
if ( * z = = ' \\ ' ) nBack + + ;
}
2014-01-10 23:21:00 +00:00
lemon_sprintf ( zLine , " #line %d " , psp - > tokenlineno ) ;
2008-08-13 20:09:06 +00:00
nLine = lemonStrlen ( zLine ) ;
n + = nLine + lemonStrlen ( psp - > filename ) + nBack ;
2008-04-27 22:19:44 +00:00
}
2010-02-14 17:14:22 +00:00
* psp - > declargslot = ( char * ) realloc ( * psp - > declargslot , n ) ;
zBuf = * psp - > declargslot + nOld ;
2008-07-14 12:21:08 +00:00
if ( addLineMacro ) {
2008-04-27 22:19:44 +00:00
if ( nOld & & zBuf [ - 1 ] ! = ' \n ' ) {
* ( zBuf + + ) = ' \n ' ;
}
memcpy ( zBuf , zLine , nLine ) ;
zBuf + = nLine ;
* ( zBuf + + ) = ' " ' ;
for ( z = psp - > filename ; * z ; z + + ) {
if ( * z = = ' \\ ' ) {
* ( zBuf + + ) = ' \\ ' ;
}
* ( zBuf + + ) = * z ;
}
* ( zBuf + + ) = ' " ' ;
* ( zBuf + + ) = ' \n ' ;
}
2008-07-01 17:13:57 +00:00
if ( psp - > decllinenoslot & & psp - > decllinenoslot [ 0 ] = = 0 ) {
psp - > decllinenoslot [ 0 ] = psp - > tokenlineno ;
}
2008-04-27 22:19:44 +00:00
memcpy ( zBuf , zNew , nNew ) ;
zBuf + = nNew ;
* zBuf = 0 ;
psp - > state = WAITING_FOR_DECL_OR_RULE ;
2000-05-29 14:26:00 +00:00
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Illegal argument to %%%s: %s " , psp - > declkeyword , x ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
}
break ;
2002-06-06 18:54:39 +00:00
case WAITING_FOR_FALLBACK_ID :
if ( x [ 0 ] = = ' . ' ) {
psp - > state = WAITING_FOR_DECL_OR_RULE ;
2015-10-29 13:48:15 +00:00
} else if ( ! ISUPPER ( x [ 0 ] ) ) {
2002-06-06 18:54:39 +00:00
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" %%fallback argument \" %s \" should be a token " , x ) ;
psp - > errorcnt + + ;
} else {
struct symbol * sp = Symbol_new ( x ) ;
if ( psp - > fallback = = 0 ) {
psp - > fallback = sp ;
} else if ( sp - > fallback ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" More than one fallback assigned to token %s " , x ) ;
psp - > errorcnt + + ;
} else {
sp - > fallback = psp - > fallback ;
psp - > gp - > has_fallback = 1 ;
}
}
break ;
2017-08-02 03:21:11 +00:00
case WAITING_FOR_TOKEN_NAME :
/* Tokens do not have to be declared before use. But they can be
* * in order to control their assigned integer number . The number for
* * each token is assigned when it is first seen . So by including
* *
2021-03-28 20:44:01 +00:00
* * % token ONE TWO THREE .
2017-08-02 03:21:11 +00:00
* *
* * early in the grammar file , that assigns small consecutive values
* * to each of the tokens ONE TWO and THREE .
*/
if ( x [ 0 ] = = ' . ' ) {
psp - > state = WAITING_FOR_DECL_OR_RULE ;
} else if ( ! ISUPPER ( x [ 0 ] ) ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" %%token argument \" %s \" should be a token " , x ) ;
psp - > errorcnt + + ;
} else {
( void ) Symbol_new ( x ) ;
}
break ;
2006-06-10 13:29:31 +00:00
case WAITING_FOR_WILDCARD_ID :
if ( x [ 0 ] = = ' . ' ) {
psp - > state = WAITING_FOR_DECL_OR_RULE ;
2015-10-29 13:48:15 +00:00
} else if ( ! ISUPPER ( x [ 0 ] ) ) {
2006-06-10 13:29:31 +00:00
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" %%wildcard argument \" %s \" should be a token " , x ) ;
psp - > errorcnt + + ;
} else {
struct symbol * sp = Symbol_new ( x ) ;
if ( psp - > gp - > wildcard = = 0 ) {
psp - > gp - > wildcard = sp ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Extra wildcard to token: %s " , x ) ;
psp - > errorcnt + + ;
}
}
break ;
2014-01-11 03:06:18 +00:00
case WAITING_FOR_CLASS_ID :
2015-10-29 13:48:15 +00:00
if ( ! ISLOWER ( x [ 0 ] ) ) {
2014-01-11 03:06:18 +00:00
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
2019-05-10 16:16:19 +00:00
" %%token_class must be followed by an identifier: %s " , x ) ;
2014-01-11 03:06:18 +00:00
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
} else if ( Symbol_find ( x ) ) {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" Symbol \" %s \" already used " , x ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
} else {
psp - > tkclass = Symbol_new ( x ) ;
psp - > tkclass - > type = MULTITERMINAL ;
psp - > state = WAITING_FOR_CLASS_TOKEN ;
}
break ;
case WAITING_FOR_CLASS_TOKEN :
if ( x [ 0 ] = = ' . ' ) {
psp - > state = WAITING_FOR_DECL_OR_RULE ;
2015-10-29 13:48:15 +00:00
} else if ( ISUPPER ( x [ 0 ] ) | | ( ( x [ 0 ] = = ' | ' | | x [ 0 ] = = ' / ' ) & & ISUPPER ( x [ 1 ] ) ) ) {
2014-01-11 03:06:18 +00:00
struct symbol * msp = psp - > tkclass ;
msp - > nsubsym + + ;
msp - > subsym = ( struct symbol * * ) realloc ( msp - > subsym ,
sizeof ( struct symbol * ) * msp - > nsubsym ) ;
2015-10-29 13:48:15 +00:00
if ( ! ISUPPER ( x [ 0 ] ) ) x + + ;
2014-01-11 03:06:18 +00:00
msp - > subsym [ msp - > nsubsym - 1 ] = Symbol_new ( x ) ;
} else {
ErrorMsg ( psp - > filename , psp - > tokenlineno ,
" %%token_class argument \" %s \" should be a token " , x ) ;
psp - > errorcnt + + ;
psp - > state = RESYNC_AFTER_DECL_ERROR ;
}
break ;
2000-05-29 14:26:00 +00:00
case RESYNC_AFTER_RULE_ERROR :
/* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
* * break ; */
case RESYNC_AFTER_DECL_ERROR :
if ( x [ 0 ] = = ' . ' ) psp - > state = WAITING_FOR_DECL_OR_RULE ;
if ( x [ 0 ] = = ' % ' ) psp - > state = WAITING_FOR_DECL_KEYWORD ;
break ;
}
}
2020-07-03 15:41:08 +00:00
/* The text in the input is part of the argument to an %ifdef or %ifndef.
* * Evaluate the text as a boolean expression . Return true or false .
*/
static int eval_preprocessor_boolean ( char * z , int lineno ) {
int neg = 0 ;
int res = 0 ;
int okTerm = 1 ;
int i ;
for ( i = 0 ; z [ i ] ! = 0 ; i + + ) {
if ( ISSPACE ( z [ i ] ) ) continue ;
if ( z [ i ] = = ' ! ' ) {
if ( ! okTerm ) goto pp_syntax_error ;
neg = ! neg ;
continue ;
}
if ( z [ i ] = = ' | ' & & z [ i + 1 ] = = ' | ' ) {
if ( okTerm ) goto pp_syntax_error ;
if ( res ) return 1 ;
i + + ;
okTerm = 1 ;
continue ;
}
if ( z [ i ] = = ' & ' & & z [ i + 1 ] = = ' & ' ) {
if ( okTerm ) goto pp_syntax_error ;
if ( ! res ) return 0 ;
i + + ;
okTerm = 1 ;
continue ;
}
if ( z [ i ] = = ' ( ' ) {
int k ;
int n = 1 ;
if ( ! okTerm ) goto pp_syntax_error ;
for ( k = i + 1 ; z [ k ] ; k + + ) {
if ( z [ k ] = = ' ) ' ) {
n - - ;
if ( n = = 0 ) {
z [ k ] = 0 ;
res = eval_preprocessor_boolean ( & z [ i + 1 ] , - 1 ) ;
z [ k ] = ' ) ' ;
if ( res < 0 ) {
i = i - res ;
goto pp_syntax_error ;
}
i = k ;
break ;
}
} else if ( z [ k ] = = ' ( ' ) {
n + + ;
} else if ( z [ k ] = = 0 ) {
i = k ;
goto pp_syntax_error ;
}
}
if ( neg ) {
res = ! res ;
neg = 0 ;
}
okTerm = 0 ;
continue ;
}
if ( ISALPHA ( z [ i ] ) ) {
int j , k , n ;
if ( ! okTerm ) goto pp_syntax_error ;
for ( k = i + 1 ; ISALNUM ( z [ k ] ) | | z [ k ] = = ' _ ' ; k + + ) { }
n = k - i ;
res = 0 ;
for ( j = 0 ; j < nDefine ; j + + ) {
if ( strncmp ( azDefine [ j ] , & z [ i ] , n ) = = 0 & & azDefine [ j ] [ n ] = = 0 ) {
2023-06-08 12:52:28 +00:00
if ( ! bDefineUsed [ j ] ) {
bDefineUsed [ j ] = 1 ;
nDefineUsed + + ;
}
2020-07-03 15:41:08 +00:00
res = 1 ;
break ;
}
}
i = k - 1 ;
if ( neg ) {
res = ! res ;
neg = 0 ;
}
okTerm = 0 ;
continue ;
}
goto pp_syntax_error ;
}
return res ;
pp_syntax_error :
if ( lineno > 0 ) {
fprintf ( stderr , " %%if syntax error on line %d. \n " , lineno ) ;
fprintf ( stderr , " %.*s <-- syntax error here \n " , i + 1 , z ) ;
exit ( 1 ) ;
} else {
return - ( i + 1 ) ;
}
}
2008-07-14 12:27:51 +00:00
/* Run the preprocessor over the input file text. The global variables
2004-07-20 12:45:22 +00:00
* * azDefine [ 0 ] through azDefine [ nDefine - 1 ] contains the names of all defined
* * macros . This routine looks for " %ifdef " and " %ifndef " and " %endif " and
* * comments them out . Text in between is also commented out as appropriate .
*/
2005-01-23 22:41:37 +00:00
static void preprocess_input ( char * z ) {
2020-07-03 15:41:08 +00:00
int i , j , k ;
2004-07-20 12:45:22 +00:00
int exclude = 0 ;
2007-09-20 11:34:17 +00:00
int start = 0 ;
2004-07-20 12:45:22 +00:00
int lineno = 1 ;
2007-09-20 11:34:17 +00:00
int start_lineno = 1 ;
2004-07-20 12:45:22 +00:00
for ( i = 0 ; z [ i ] ; i + + ) {
if ( z [ i ] = = ' \n ' ) lineno + + ;
if ( z [ i ] ! = ' % ' | | ( i > 0 & & z [ i - 1 ] ! = ' \n ' ) ) continue ;
2015-10-29 13:48:15 +00:00
if ( strncmp ( & z [ i ] , " %endif " , 6 ) = = 0 & & ISSPACE ( z [ i + 6 ] ) ) {
2004-07-20 12:45:22 +00:00
if ( exclude ) {
exclude - - ;
if ( exclude = = 0 ) {
for ( j = start ; j < i ; j + + ) if ( z [ j ] ! = ' \n ' ) z [ j ] = ' ' ;
}
}
for ( j = i ; z [ j ] & & z [ j ] ! = ' \n ' ; j + + ) z [ j ] = ' ' ;
2020-07-03 15:41:08 +00:00
} else if ( strncmp ( & z [ i ] , " %else " , 5 ) = = 0 & & ISSPACE ( z [ i + 5 ] ) ) {
if ( exclude = = 1 ) {
exclude = 0 ;
for ( j = start ; j < i ; j + + ) if ( z [ j ] ! = ' \n ' ) z [ j ] = ' ' ;
} else if ( exclude = = 0 ) {
exclude = 1 ;
start = i ;
start_lineno = lineno ;
}
for ( j = i ; z [ j ] & & z [ j ] ! = ' \n ' ; j + + ) z [ j ] = ' ' ;
} else if ( strncmp ( & z [ i ] , " %ifdef " , 7 ) = = 0
| | strncmp ( & z [ i ] , " %if " , 4 ) = = 0
| | strncmp ( & z [ i ] , " %ifndef " , 8 ) = = 0 ) {
2004-07-20 12:45:22 +00:00
if ( exclude ) {
exclude + + ;
} else {
2020-07-03 15:41:08 +00:00
int isNot ;
int iBool ;
for ( j = i ; z [ j ] & & ! ISSPACE ( z [ j ] ) ; j + + ) { }
iBool = j ;
isNot = ( j = = i + 7 ) ;
while ( z [ j ] & & z [ j ] ! = ' \n ' ) { j + + ; }
k = z [ j ] ;
z [ j ] = 0 ;
exclude = eval_preprocessor_boolean ( & z [ iBool ] , lineno ) ;
z [ j ] = k ;
if ( ! isNot ) exclude = ! exclude ;
2004-07-20 12:45:22 +00:00
if ( exclude ) {
start = i ;
start_lineno = lineno ;
}
}
for ( j = i ; z [ j ] & & z [ j ] ! = ' \n ' ; j + + ) z [ j ] = ' ' ;
}
}
if ( exclude ) {
fprintf ( stderr , " unterminated %%ifdef starting on line %d \n " , start_lineno ) ;
exit ( 1 ) ;
}
}
2000-05-29 14:26:00 +00:00
/* In spite of its name, this function is really a scanner. It read
* * in the entire input file ( all at once ) then tokenizes it . Each
* * token is passed to the function " parseonetoken " which builds all
* * the appropriate data structures in the global state vector " gp " .
*/
2010-02-14 17:14:22 +00:00
void Parse ( struct lemon * gp )
2000-05-29 14:26:00 +00:00
{
struct pstate ps ;
FILE * fp ;
char * filebuf ;
2015-01-12 18:02:52 +00:00
unsigned int filesize ;
2000-05-29 14:26:00 +00:00
int lineno ;
int c ;
char * cp , * nextcp ;
int startline = 0 ;
2007-09-20 11:34:17 +00:00
memset ( & ps , ' \0 ' , sizeof ( ps ) ) ;
2000-05-29 14:26:00 +00:00
ps . gp = gp ;
ps . filename = gp - > filename ;
ps . errorcnt = 0 ;
ps . state = INITIALIZE ;
/* Begin by reading the input file */
fp = fopen ( ps . filename , " rb " ) ;
if ( fp = = 0 ) {
ErrorMsg ( ps . filename , 0 , " Can't open this file for reading. " ) ;
gp - > errorcnt + + ;
return ;
}
fseek ( fp , 0 , 2 ) ;
filesize = ftell ( fp ) ;
rewind ( fp ) ;
filebuf = ( char * ) malloc ( filesize + 1 ) ;
2014-01-11 12:52:25 +00:00
if ( filesize > 100000000 | | filebuf = = 0 ) {
ErrorMsg ( ps . filename , 0 , " Input file too large. " ) ;
2018-09-08 16:55:18 +00:00
free ( filebuf ) ;
2000-05-29 14:26:00 +00:00
gp - > errorcnt + + ;
2011-08-30 00:58:58 +00:00
fclose ( fp ) ;
2000-05-29 14:26:00 +00:00
return ;
}
if ( fread ( filebuf , 1 , filesize , fp ) ! = filesize ) {
ErrorMsg ( ps . filename , 0 , " Can't read in all %d bytes of this file. " ,
filesize ) ;
free ( filebuf ) ;
gp - > errorcnt + + ;
2011-08-30 00:58:58 +00:00
fclose ( fp ) ;
2000-05-29 14:26:00 +00:00
return ;
}
fclose ( fp ) ;
filebuf [ filesize ] = 0 ;
2004-07-20 12:45:22 +00:00
/* Make an initial pass through the file to handle %ifdef and %ifndef */
preprocess_input ( filebuf ) ;
2020-07-03 15:41:08 +00:00
if ( gp - > printPreprocessed ) {
printf ( " %s \n " , filebuf ) ;
return ;
}
2004-07-20 12:45:22 +00:00
2000-05-29 14:26:00 +00:00
/* Now scan the text of the input file */
lineno = 1 ;
for ( cp = filebuf ; ( c = * cp ) ! = 0 ; ) {
if ( c = = ' \n ' ) lineno + + ; /* Keep track of the line number */
2015-10-29 13:48:15 +00:00
if ( ISSPACE ( c ) ) { cp + + ; continue ; } /* Skip all white space */
2000-05-29 14:26:00 +00:00
if ( c = = ' / ' & & cp [ 1 ] = = ' / ' ) { /* Skip C++ style comments */
cp + = 2 ;
while ( ( c = * cp ) ! = 0 & & c ! = ' \n ' ) cp + + ;
continue ;
}
if ( c = = ' / ' & & cp [ 1 ] = = ' * ' ) { /* Skip C style comments */
cp + = 2 ;
2022-04-07 14:13:32 +00:00
if ( ( * cp ) = = ' / ' ) cp + + ;
2000-05-29 14:26:00 +00:00
while ( ( c = * cp ) ! = 0 & & ( c ! = ' / ' | | cp [ - 1 ] ! = ' * ' ) ) {
if ( c = = ' \n ' ) lineno + + ;
cp + + ;
}
if ( c ) cp + + ;
continue ;
}
ps . tokenstart = cp ; /* Mark the beginning of the token */
ps . tokenlineno = lineno ; /* Linenumber on which token begins */
if ( c = = ' \" ' ) { /* String literals */
cp + + ;
while ( ( c = * cp ) ! = 0 & & c ! = ' \" ' ) {
if ( c = = ' \n ' ) lineno + + ;
cp + + ;
}
if ( c = = 0 ) {
ErrorMsg ( ps . filename , startline ,
2019-12-12 00:20:40 +00:00
" String starting on this line is not terminated before "
" the end of the file. " ) ;
2000-05-29 14:26:00 +00:00
ps . errorcnt + + ;
nextcp = cp ;
} else {
nextcp = cp + 1 ;
}
} else if ( c = = ' { ' ) { /* A block of C code */
int level ;
cp + + ;
for ( level = 1 ; ( c = * cp ) ! = 0 & & ( level > 1 | | c ! = ' } ' ) ; cp + + ) {
if ( c = = ' \n ' ) lineno + + ;
else if ( c = = ' { ' ) level + + ;
else if ( c = = ' } ' ) level - - ;
else if ( c = = ' / ' & & cp [ 1 ] = = ' * ' ) { /* Skip comments */
int prevc ;
cp = & cp [ 2 ] ;
prevc = 0 ;
while ( ( c = * cp ) ! = 0 & & ( c ! = ' / ' | | prevc ! = ' * ' ) ) {
if ( c = = ' \n ' ) lineno + + ;
prevc = c ;
cp + + ;
2012-08-20 15:53:54 +00:00
}
} else if ( c = = ' / ' & & cp [ 1 ] = = ' / ' ) { /* Skip C++ style comments too */
2000-05-29 14:26:00 +00:00
cp = & cp [ 2 ] ;
while ( ( c = * cp ) ! = 0 & & c ! = ' \n ' ) cp + + ;
if ( c ) lineno + + ;
2012-08-20 15:53:54 +00:00
} else if ( c = = ' \' ' | | c = = ' \" ' ) { /* String a character literals */
2000-05-29 14:26:00 +00:00
int startchar , prevc ;
startchar = c ;
prevc = 0 ;
for ( cp + + ; ( c = * cp ) ! = 0 & & ( c ! = startchar | | prevc = = ' \\ ' ) ; cp + + ) {
if ( c = = ' \n ' ) lineno + + ;
if ( prevc = = ' \\ ' ) prevc = 0 ;
else prevc = c ;
2012-08-20 15:53:54 +00:00
}
}
2000-05-29 14:26:00 +00:00
}
if ( c = = 0 ) {
2001-04-03 16:53:21 +00:00
ErrorMsg ( ps . filename , ps . tokenlineno ,
2019-12-12 00:20:40 +00:00
" C code starting on this line is not terminated before "
" the end of the file. " ) ;
2000-05-29 14:26:00 +00:00
ps . errorcnt + + ;
nextcp = cp ;
} else {
nextcp = cp + 1 ;
}
2015-10-29 13:48:15 +00:00
} else if ( ISALNUM ( c ) ) { /* Identifiers */
while ( ( c = * cp ) ! = 0 & & ( ISALNUM ( c ) | | c = = ' _ ' ) ) cp + + ;
2000-05-29 14:26:00 +00:00
nextcp = cp ;
} else if ( c = = ' : ' & & cp [ 1 ] = = ' : ' & & cp [ 2 ] = = ' = ' ) { /* The operator "::=" */
cp + = 3 ;
nextcp = cp ;
2015-10-29 13:48:15 +00:00
} else if ( ( c = = ' / ' | | c = = ' | ' ) & & ISALPHA ( cp [ 1 ] ) ) {
2005-11-06 04:06:59 +00:00
cp + = 2 ;
2015-10-29 13:48:15 +00:00
while ( ( c = * cp ) ! = 0 & & ( ISALNUM ( c ) | | c = = ' _ ' ) ) cp + + ;
2005-11-06 04:06:59 +00:00
nextcp = cp ;
2000-05-29 14:26:00 +00:00
} else { /* All other (one character) operators */
cp + + ;
nextcp = cp ;
}
c = * cp ;
* cp = 0 ; /* Null terminate the token */
parseonetoken ( & ps ) ; /* Parse the token */
2015-01-12 18:02:52 +00:00
* cp = ( char ) c ; /* Restore the buffer */
2000-05-29 14:26:00 +00:00
cp = nextcp ;
}
free ( filebuf ) ; /* Release the buffer after parsing */
gp - > rule = ps . firstrule ;
gp - > errorcnt = ps . errorcnt ;
}
/*************************** From the file "plink.c" *********************/
/*
* * Routines processing configuration follow - set propagation links
* * in the LEMON parser generator .
*/
static struct plink * plink_freelist = 0 ;
/* Allocate a new plink */
2017-04-14 19:44:15 +00:00
struct plink * Plink_new ( void ) {
2010-02-14 17:14:22 +00:00
struct plink * newlink ;
2000-05-29 14:26:00 +00:00
if ( plink_freelist = = 0 ) {
int i ;
int amt = 100 ;
2007-12-21 00:02:11 +00:00
plink_freelist = ( struct plink * ) calloc ( amt , sizeof ( struct plink ) ) ;
2000-05-29 14:26:00 +00:00
if ( plink_freelist = = 0 ) {
fprintf ( stderr ,
" Unable to allocate memory for a new follow-set propagation link. \n " ) ;
exit ( 1 ) ;
}
for ( i = 0 ; i < amt - 1 ; i + + ) plink_freelist [ i ] . next = & plink_freelist [ i + 1 ] ;
plink_freelist [ amt - 1 ] . next = 0 ;
}
2010-02-14 17:14:22 +00:00
newlink = plink_freelist ;
2000-05-29 14:26:00 +00:00
plink_freelist = plink_freelist - > next ;
2010-02-14 17:14:22 +00:00
return newlink ;
2000-05-29 14:26:00 +00:00
}
/* Add a plink to a plink list */
2010-02-14 17:14:22 +00:00
void Plink_add ( struct plink * * plpp , struct config * cfp )
2000-05-29 14:26:00 +00:00
{
2010-02-14 17:14:22 +00:00
struct plink * newlink ;
newlink = Plink_new ( ) ;
newlink - > next = * plpp ;
* plpp = newlink ;
newlink - > cfp = cfp ;
2000-05-29 14:26:00 +00:00
}
/* Transfer every plink on the list "from" to the list "to" */
2010-02-14 17:14:22 +00:00
void Plink_copy ( struct plink * * to , struct plink * from )
2000-05-29 14:26:00 +00:00
{
struct plink * nextpl ;
while ( from ) {
nextpl = from - > next ;
from - > next = * to ;
* to = from ;
from = nextpl ;
}
}
/* Delete every plink on the list */
2010-02-14 17:14:22 +00:00
void Plink_delete ( struct plink * plp )
2000-05-29 14:26:00 +00:00
{
struct plink * nextpl ;
while ( plp ) {
nextpl = plp - > next ;
plp - > next = plink_freelist ;
plink_freelist = plp ;
plp = nextpl ;
}
}
/*********************** From the file "report.c" **************************/
/*
* * Procedures for generating reports and tables in the LEMON parser generator .
*/
/* Generate a filename with the given suffix. Space to hold the
* * name comes from malloc ( ) and must be freed by the calling
* * function .
*/
2010-02-14 17:14:22 +00:00
PRIVATE char * file_makename ( struct lemon * lemp , const char * suffix )
2000-05-29 14:26:00 +00:00
{
char * name ;
char * cp ;
2018-04-20 20:47:49 +00:00
char * filename = lemp - > filename ;
int sz ;
if ( outputDir ) {
cp = strrchr ( filename , ' / ' ) ;
if ( cp ) filename = cp + 1 ;
}
sz = lemonStrlen ( filename ) ;
sz + = lemonStrlen ( suffix ) ;
if ( outputDir ) sz + = lemonStrlen ( outputDir ) + 1 ;
sz + = 5 ;
name = ( char * ) malloc ( sz ) ;
2000-05-29 14:26:00 +00:00
if ( name = = 0 ) {
fprintf ( stderr , " Can't allocate space for a filename. \n " ) ;
exit ( 1 ) ;
}
2018-04-20 20:47:49 +00:00
name [ 0 ] = 0 ;
if ( outputDir ) {
lemon_strcpy ( name , outputDir ) ;
lemon_strcat ( name , " / " ) ;
}
lemon_strcat ( name , filename ) ;
2000-05-29 14:26:00 +00:00
cp = strrchr ( name , ' . ' ) ;
if ( cp ) * cp = 0 ;
2014-01-10 23:21:00 +00:00
lemon_strcat ( name , suffix ) ;
2000-05-29 14:26:00 +00:00
return name ;
}
/* Open a file with a name based on the name of the input file,
* * but with a different ( specified ) suffix , and return a pointer
* * to the stream */
2010-02-14 17:14:22 +00:00
PRIVATE FILE * file_open (
struct lemon * lemp ,
const char * suffix ,
const char * mode
) {
2000-05-29 14:26:00 +00:00
FILE * fp ;
if ( lemp - > outname ) free ( lemp - > outname ) ;
lemp - > outname = file_makename ( lemp , suffix ) ;
fp = fopen ( lemp - > outname , mode ) ;
if ( fp = = 0 & & * mode = = ' w ' ) {
fprintf ( stderr , " Can't open file \" %s \" . \n " , lemp - > outname ) ;
lemp - > errorcnt + + ;
return 0 ;
}
return fp ;
}
2017-12-24 23:38:10 +00:00
/* Print the text of a rule
*/
void rule_print ( FILE * out , struct rule * rp ) {
int i , j ;
fprintf ( out , " %s " , rp - > lhs - > name ) ;
/* if( rp->lhsalias ) fprintf(out,"(%s)",rp->lhsalias); */
fprintf ( out , " ::= " ) ;
for ( i = 0 ; i < rp - > nrhs ; i + + ) {
struct symbol * sp = rp - > rhs [ i ] ;
if ( sp - > type = = MULTITERMINAL ) {
fprintf ( out , " %s " , sp - > subsym [ 0 ] - > name ) ;
for ( j = 1 ; j < sp - > nsubsym ; j + + ) {
fprintf ( out , " |%s " , sp - > subsym [ j ] - > name ) ;
}
} else {
fprintf ( out , " %s " , sp - > name ) ;
}
/* if( rp->rhsalias[i] ) fprintf(out,"(%s)",rp->rhsalias[i]); */
}
}
2017-04-14 19:46:12 +00:00
/* Duplicate the input file without comments and without actions
2000-05-29 14:26:00 +00:00
* * on rules */
2010-02-14 17:14:22 +00:00
void Reprint ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
struct rule * rp ;
struct symbol * sp ;
int i , j , maxlen , len , ncolumns , skip ;
printf ( " // Reprint of input file \" %s \" . \n // Symbols: \n " , lemp - > filename ) ;
maxlen = 10 ;
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
sp = lemp - > symbols [ i ] ;
2008-08-13 20:09:06 +00:00
len = lemonStrlen ( sp - > name ) ;
2000-05-29 14:26:00 +00:00
if ( len > maxlen ) maxlen = len ;
}
ncolumns = 76 / ( maxlen + 5 ) ;
if ( ncolumns < 1 ) ncolumns = 1 ;
skip = ( lemp - > nsymbol + ncolumns - 1 ) / ncolumns ;
for ( i = 0 ; i < skip ; i + + ) {
printf ( " // " ) ;
for ( j = i ; j < lemp - > nsymbol ; j + = skip ) {
sp = lemp - > symbols [ j ] ;
assert ( sp - > index = = j ) ;
printf ( " %3d %-*.*s " , j , maxlen , maxlen , sp - > name ) ;
}
printf ( " \n " ) ;
}
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
2017-12-24 23:38:10 +00:00
rule_print ( stdout , rp ) ;
2000-05-29 14:26:00 +00:00
printf ( " . " ) ;
if ( rp - > precsym ) printf ( " [%s] " , rp - > precsym - > name ) ;
2005-11-06 04:06:59 +00:00
/* if( rp->code ) printf("\n %s",rp->code); */
2000-05-29 14:26:00 +00:00
printf ( " \n " ) ;
}
}
2015-09-07 14:22:24 +00:00
/* Print a single rule.
*/
void RulePrint ( FILE * fp , struct rule * rp , int iCursor ) {
2005-11-06 04:06:59 +00:00
struct symbol * sp ;
int i , j ;
2000-05-29 14:26:00 +00:00
fprintf ( fp , " %s ::= " , rp - > lhs - > name ) ;
for ( i = 0 ; i < = rp - > nrhs ; i + + ) {
2015-09-07 14:22:24 +00:00
if ( i = = iCursor ) fprintf ( fp , " * " ) ;
2000-05-29 14:26:00 +00:00
if ( i = = rp - > nrhs ) break ;
2005-11-06 04:06:59 +00:00
sp = rp - > rhs [ i ] ;
if ( sp - > type = = MULTITERMINAL ) {
2014-01-11 03:06:18 +00:00
fprintf ( fp , " %s " , sp - > subsym [ 0 ] - > name ) ;
2005-11-06 04:06:59 +00:00
for ( j = 1 ; j < sp - > nsubsym ; j + + ) {
fprintf ( fp , " |%s " , sp - > subsym [ j ] - > name ) ;
}
2014-01-11 03:06:18 +00:00
} else {
fprintf ( fp , " %s " , sp - > name ) ;
2005-11-06 04:06:59 +00:00
}
2000-05-29 14:26:00 +00:00
}
}
2015-09-07 14:22:24 +00:00
/* Print the rule for a configuration.
*/
void ConfigPrint ( FILE * fp , struct config * cfp ) {
RulePrint ( fp , cfp - > rp , cfp - > dot ) ;
}
2000-05-29 14:26:00 +00:00
/* #define TEST */
2005-11-06 04:06:59 +00:00
#if 0
2000-05-29 14:26:00 +00:00
/* Print a set */
PRIVATE void SetPrint ( out , set , lemp )
FILE * out ;
char * set ;
struct lemon * lemp ;
{
int i ;
char * spacer ;
spacer = " " ;
fprintf ( out , " %12s[ " , " " ) ;
for ( i = 0 ; i < lemp - > nterminal ; i + + ) {
if ( SetFind ( set , i ) ) {
fprintf ( out , " %s%s " , spacer , lemp - > symbols [ i ] - > name ) ;
spacer = " " ;
}
}
fprintf ( out , " ] \n " ) ;
}
/* Print a plink chain */
PRIVATE void PlinkPrint ( out , plp , tag )
FILE * out ;
struct plink * plp ;
char * tag ;
{
while ( plp ) {
2005-11-05 15:03:59 +00:00
fprintf ( out , " %12s%s (state %2d) " , " " , tag , plp - > cfp - > stp - > statenum ) ;
2000-05-29 14:26:00 +00:00
ConfigPrint ( out , plp - > cfp ) ;
fprintf ( out , " \n " ) ;
plp = plp - > next ;
}
}
# endif
/* Print an action to the given file descriptor. Return FALSE if
* * nothing was actually printed .
*/
2015-09-07 14:22:24 +00:00
int PrintAction (
struct action * ap , /* The action to print */
FILE * fp , /* Print the action here */
2015-09-07 18:23:37 +00:00
int indent /* Indent by this amount */
2015-09-07 14:22:24 +00:00
) {
2000-05-29 14:26:00 +00:00
int result = 1 ;
switch ( ap - > type ) {
2015-09-07 14:22:24 +00:00
case SHIFT : {
struct state * stp = ap - > x . stp ;
2015-09-07 18:23:37 +00:00
fprintf ( fp , " %*s shift %-7d " , indent , ap - > sp - > name , stp - > statenum ) ;
2000-05-29 14:26:00 +00:00
break ;
2015-09-07 14:22:24 +00:00
}
case REDUCE : {
struct rule * rp = ap - > x . rp ;
2016-03-16 19:45:54 +00:00
fprintf ( fp , " %*s reduce %-7d " , indent , ap - > sp - > name , rp - > iRule ) ;
2015-09-07 18:23:37 +00:00
RulePrint ( fp , rp , - 1 ) ;
break ;
}
case SHIFTREDUCE : {
struct rule * rp = ap - > x . rp ;
2016-03-16 19:45:54 +00:00
fprintf ( fp , " %*s shift-reduce %-7d " , indent , ap - > sp - > name , rp - > iRule ) ;
2015-09-07 18:23:37 +00:00
RulePrint ( fp , rp , - 1 ) ;
2000-05-29 14:26:00 +00:00
break ;
2015-09-07 14:22:24 +00:00
}
2000-05-29 14:26:00 +00:00
case ACCEPT :
fprintf ( fp , " %*s accept " , indent , ap - > sp - > name ) ;
break ;
case ERROR :
fprintf ( fp , " %*s error " , indent , ap - > sp - > name ) ;
break ;
2007-12-21 00:02:11 +00:00
case SRCONFLICT :
case RRCONFLICT :
2015-09-07 18:23:37 +00:00
fprintf ( fp , " %*s reduce %-7d ** Parsing conflict ** " ,
2016-03-16 19:45:54 +00:00
indent , ap - > sp - > name , ap - > x . rp - > iRule ) ;
2000-05-29 14:26:00 +00:00
break ;
2007-12-21 00:02:11 +00:00
case SSCONFLICT :
2017-04-14 19:46:12 +00:00
fprintf ( fp , " %*s shift %-7d ** Parsing conflict ** " ,
2007-12-21 00:02:11 +00:00
indent , ap - > sp - > name , ap - > x . stp - > statenum ) ;
break ;
2000-05-29 14:26:00 +00:00
case SH_RESOLVED :
2010-07-18 11:35:53 +00:00
if ( showPrecedenceConflict ) {
2015-09-07 18:23:37 +00:00
fprintf ( fp , " %*s shift %-7d -- dropped by precedence " ,
2010-07-18 11:35:53 +00:00
indent , ap - > sp - > name , ap - > x . stp - > statenum ) ;
} else {
result = 0 ;
}
break ;
2000-05-29 14:26:00 +00:00
case RD_RESOLVED :
2010-07-18 11:35:53 +00:00
if ( showPrecedenceConflict ) {
2015-09-07 14:22:24 +00:00
fprintf ( fp , " %*s reduce %-7d -- dropped by precedence " ,
2016-03-16 19:45:54 +00:00
indent , ap - > sp - > name , ap - > x . rp - > iRule ) ;
2010-07-18 11:35:53 +00:00
} else {
result = 0 ;
}
break ;
2000-05-29 14:26:00 +00:00
case NOT_USED :
result = 0 ;
break ;
}
2016-05-23 16:15:02 +00:00
if ( result & & ap - > spOpt ) {
fprintf ( fp , " /* because %s==%s */ " , ap - > sp - > name , ap - > spOpt - > name ) ;
}
2000-05-29 14:26:00 +00:00
return result ;
}
2015-09-07 18:23:37 +00:00
/* Generate the "*.out" log file */
2010-02-14 17:14:22 +00:00
void ReportOutput ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
2018-04-21 20:24:19 +00:00
int i , n ;
2000-05-29 14:26:00 +00:00
struct state * stp ;
struct config * cfp ;
struct action * ap ;
2018-04-06 19:12:55 +00:00
struct rule * rp ;
2000-05-29 14:26:00 +00:00
FILE * fp ;
2015-09-07 18:23:37 +00:00
2004-09-10 00:14:04 +00:00
fp = file_open ( lemp , " .out " , " wb " ) ;
2000-05-29 14:26:00 +00:00
if ( fp = = 0 ) return ;
2015-09-07 18:23:37 +00:00
for ( i = 0 ; i < lemp - > nxstate ; i + + ) {
2000-05-29 14:26:00 +00:00
stp = lemp - > sorted [ i ] ;
2005-11-05 15:03:59 +00:00
fprintf ( fp , " State %d: \n " , stp - > statenum ) ;
2000-05-29 14:26:00 +00:00
if ( lemp - > basisflag ) cfp = stp - > bp ;
else cfp = stp - > cfp ;
while ( cfp ) {
char buf [ 20 ] ;
if ( cfp - > dot = = cfp - > rp - > nrhs ) {
2016-03-16 19:45:54 +00:00
lemon_sprintf ( buf , " (%d) " , cfp - > rp - > iRule ) ;
2000-05-29 14:26:00 +00:00
fprintf ( fp , " %5s " , buf ) ;
} else {
fprintf ( fp , " " ) ;
}
ConfigPrint ( fp , cfp ) ;
fprintf ( fp , " \n " ) ;
2005-11-06 04:06:59 +00:00
#if 0
2000-05-29 14:26:00 +00:00
SetPrint ( fp , cfp - > fws , lemp ) ;
PlinkPrint ( fp , cfp - > fplp , " To " ) ;
PlinkPrint ( fp , cfp - > bplp , " From " ) ;
# endif
if ( lemp - > basisflag ) cfp = cfp - > bp ;
else cfp = cfp - > next ;
}
fprintf ( fp , " \n " ) ;
for ( ap = stp - > ap ; ap ; ap = ap - > next ) {
2015-09-07 18:23:37 +00:00
if ( PrintAction ( ap , fp , 30 ) ) fprintf ( fp , " \n " ) ;
2000-05-29 14:26:00 +00:00
}
fprintf ( fp , " \n " ) ;
}
2007-07-18 18:16:29 +00:00
fprintf ( fp , " ---------------------------------------------------- \n " ) ;
fprintf ( fp , " Symbols: \n " ) ;
2018-04-21 20:24:19 +00:00
fprintf ( fp , " The first-set of non-terminals is shown after the name. \n \n " ) ;
2007-07-18 18:16:29 +00:00
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
int j ;
struct symbol * sp ;
sp = lemp - > symbols [ i ] ;
fprintf ( fp , " %3d: %s " , i , sp - > name ) ;
if ( sp - > type = = NONTERMINAL ) {
fprintf ( fp , " : " ) ;
if ( sp - > lambda ) {
fprintf ( fp , " <lambda> " ) ;
}
for ( j = 0 ; j < lemp - > nterminal ; j + + ) {
if ( sp - > firstset & & SetFind ( sp - > firstset , j ) ) {
fprintf ( fp , " %s " , lemp - > symbols [ j ] - > name ) ;
}
}
}
2018-04-06 19:12:55 +00:00
if ( sp - > prec > = 0 ) fprintf ( fp , " (precedence=%d) " , sp - > prec ) ;
2007-07-18 18:16:29 +00:00
fprintf ( fp , " \n " ) ;
}
2018-04-06 19:12:55 +00:00
fprintf ( fp , " ---------------------------------------------------- \n " ) ;
2018-04-21 20:24:19 +00:00
fprintf ( fp , " Syntax-only Symbols: \n " ) ;
fprintf ( fp , " The following symbols never carry semantic content. \n \n " ) ;
for ( i = n = 0 ; i < lemp - > nsymbol ; i + + ) {
int w ;
struct symbol * sp = lemp - > symbols [ i ] ;
if ( sp - > bContent ) continue ;
w = ( int ) strlen ( sp - > name ) ;
if ( n > 0 & & n + w > 75 ) {
fprintf ( fp , " \n " ) ;
n = 0 ;
}
if ( n > 0 ) {
fprintf ( fp , " " ) ;
n + + ;
}
fprintf ( fp , " %s " , sp - > name ) ;
n + = w ;
}
if ( n > 0 ) fprintf ( fp , " \n " ) ;
fprintf ( fp , " ---------------------------------------------------- \n " ) ;
2018-04-06 19:12:55 +00:00
fprintf ( fp , " Rules: \n " ) ;
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
fprintf ( fp , " %4d: " , rp - > iRule ) ;
rule_print ( fp , rp ) ;
fprintf ( fp , " . " ) ;
if ( rp - > precsym ) {
fprintf ( fp , " [%s precedence=%d] " ,
rp - > precsym - > name , rp - > precsym - > prec ) ;
}
fprintf ( fp , " \n " ) ;
}
2000-05-29 14:26:00 +00:00
fclose ( fp ) ;
return ;
}
/* Search for the file "name" which is in the same directory as
2021-01-07 16:10:14 +00:00
* * the executable */
2010-02-14 17:14:22 +00:00
PRIVATE char * pathsearch ( char * argv0 , char * name , int modemask )
2000-05-29 14:26:00 +00:00
{
2010-02-14 17:14:22 +00:00
const char * pathlist ;
2020-09-21 20:18:44 +00:00
char * pathbufptr = 0 ;
2020-09-20 12:10:28 +00:00
char * pathbuf = 0 ;
2000-05-29 14:26:00 +00:00
char * path , * cp ;
char c ;
# ifdef __WIN32__
cp = strrchr ( argv0 , ' \\ ' ) ;
# else
cp = strrchr ( argv0 , ' / ' ) ;
# endif
if ( cp ) {
c = * cp ;
* cp = 0 ;
2008-08-13 20:09:06 +00:00
path = ( char * ) malloc ( lemonStrlen ( argv0 ) + lemonStrlen ( name ) + 2 ) ;
2014-01-10 23:21:00 +00:00
if ( path ) lemon_sprintf ( path , " %s/%s " , argv0 , name ) ;
2000-05-29 14:26:00 +00:00
* cp = c ;
} else {
pathlist = getenv ( " PATH " ) ;
if ( pathlist = = 0 ) pathlist = " .:/bin:/usr/bin " ;
2010-02-14 17:14:22 +00:00
pathbuf = ( char * ) malloc ( lemonStrlen ( pathlist ) + 1 ) ;
2008-08-13 20:09:06 +00:00
path = ( char * ) malloc ( lemonStrlen ( pathlist ) + lemonStrlen ( name ) + 2 ) ;
2010-02-14 17:14:22 +00:00
if ( ( pathbuf ! = 0 ) & & ( path ! = 0 ) ) {
pathbufptr = pathbuf ;
2014-01-10 23:21:00 +00:00
lemon_strcpy ( pathbuf , pathlist ) ;
2010-02-14 17:14:22 +00:00
while ( * pathbuf ) {
cp = strchr ( pathbuf , ' : ' ) ;
if ( cp = = 0 ) cp = & pathbuf [ lemonStrlen ( pathbuf ) ] ;
2000-05-29 14:26:00 +00:00
c = * cp ;
* cp = 0 ;
2014-01-10 23:21:00 +00:00
lemon_sprintf ( path , " %s/%s " , pathbuf , name ) ;
2000-05-29 14:26:00 +00:00
* cp = c ;
2010-02-14 17:14:22 +00:00
if ( c = = 0 ) pathbuf [ 0 ] = 0 ;
else pathbuf = & cp [ 1 ] ;
2000-05-29 14:26:00 +00:00
if ( access ( path , modemask ) = = 0 ) break ;
}
}
2020-09-20 12:10:28 +00:00
free ( pathbufptr ) ;
2000-05-29 14:26:00 +00:00
}
return path ;
}
/* Given an action, compute the integer value for that action
* * which is to be put in the action table of the generated machine .
* * Return negative if no action should be generated .
*/
2010-02-14 17:14:22 +00:00
PRIVATE int compute_action ( struct lemon * lemp , struct action * ap )
2000-05-29 14:26:00 +00:00
{
int act ;
switch ( ap - > type ) {
2015-09-07 18:23:37 +00:00
case SHIFT : act = ap - > x . stp - > statenum ; break ;
2017-06-28 11:56:18 +00:00
case SHIFTREDUCE : {
/* Since a SHIFT is inherient after a prior REDUCE, convert any
* * SHIFTREDUCE action with a nonterminal on the LHS into a simple
* * REDUCE action : */
2021-08-27 11:26:37 +00:00
if ( ap - > sp - > index > = lemp - > nterminal
& & ( lemp - > errsym = = 0 | | ap - > sp - > index ! = lemp - > errsym - > index )
) {
2017-12-24 23:38:10 +00:00
act = lemp - > minReduce + ap - > x . rp - > iRule ;
} else {
act = lemp - > minShiftReduce + ap - > x . rp - > iRule ;
}
2017-06-28 11:56:18 +00:00
break ;
}
2017-12-24 23:38:10 +00:00
case REDUCE : act = lemp - > minReduce + ap - > x . rp - > iRule ; break ;
case ERROR : act = lemp - > errAction ; break ;
case ACCEPT : act = lemp - > accAction ; break ;
2000-05-29 14:26:00 +00:00
default : act = - 1 ; break ;
}
return act ;
}
# define LINESIZE 1000
/* The next cluster of routines are for reading the template file
* * and writing the results to the generated parser */
/* The first function transfers data from "in" to "out" until
* * a line is seen which begins with " %% " . The line number is
* * tracked .
* *
* * if name ! = 0 , then any word that begin with " Parse " is changed to
* * begin with * name instead .
*/
2010-02-14 17:14:22 +00:00
PRIVATE void tplt_xfer ( char * name , FILE * in , FILE * out , int * lineno )
2000-05-29 14:26:00 +00:00
{
int i , iStart ;
char line [ LINESIZE ] ;
while ( fgets ( line , LINESIZE , in ) & & ( line [ 0 ] ! = ' % ' | | line [ 1 ] ! = ' % ' ) ) {
( * lineno ) + + ;
iStart = 0 ;
if ( name ) {
for ( i = 0 ; line [ i ] ; i + + ) {
if ( line [ i ] = = ' P ' & & strncmp ( & line [ i ] , " Parse " , 5 ) = = 0
2015-10-29 13:48:15 +00:00
& & ( i = = 0 | | ! ISALPHA ( line [ i - 1 ] ) )
2000-05-29 14:26:00 +00:00
) {
if ( i > iStart ) fprintf ( out , " %.*s " , i - iStart , & line [ iStart ] ) ;
fprintf ( out , " %s " , name ) ;
i + = 4 ;
iStart = i + 1 ;
}
}
}
fprintf ( out , " %s " , & line [ iStart ] ) ;
}
}
2020-09-01 11:20:03 +00:00
/* Skip forward past the header of the template file to the first "%%"
*/
PRIVATE void tplt_skip_header ( FILE * in , int * lineno )
{
char line [ LINESIZE ] ;
while ( fgets ( line , LINESIZE , in ) & & ( line [ 0 ] ! = ' % ' | | line [ 1 ] ! = ' % ' ) ) {
( * lineno ) + + ;
}
}
2000-05-29 14:26:00 +00:00
/* The next function finds the template file and opens it, returning
* * a pointer to the opened file . */
2010-02-14 17:14:22 +00:00
PRIVATE FILE * tplt_open ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
static char templatename [ ] = " lempar.c " ;
char buf [ 1000 ] ;
FILE * in ;
char * tpltname ;
2020-09-20 12:10:28 +00:00
char * toFree = 0 ;
2000-05-29 14:26:00 +00:00
char * cp ;
2010-02-14 00:48:49 +00:00
/* first, see if user specified a template filename on the command line. */
if ( user_templatename ! = 0 ) {
if ( access ( user_templatename , 004 ) = = - 1 ) {
fprintf ( stderr , " Can't find the parser driver template file \" %s \" . \n " ,
user_templatename ) ;
lemp - > errorcnt + + ;
return 0 ;
}
in = fopen ( user_templatename , " rb " ) ;
if ( in = = 0 ) {
2015-09-04 18:03:45 +00:00
fprintf ( stderr , " Can't open the template file \" %s \" . \n " ,
user_templatename ) ;
2010-02-14 00:48:49 +00:00
lemp - > errorcnt + + ;
return 0 ;
}
return in ;
}
2000-05-29 14:26:00 +00:00
cp = strrchr ( lemp - > filename , ' . ' ) ;
if ( cp ) {
2014-01-10 23:21:00 +00:00
lemon_sprintf ( buf , " %.*s.lt " , ( int ) ( cp - lemp - > filename ) , lemp - > filename ) ;
2000-05-29 14:26:00 +00:00
} else {
2014-01-10 23:21:00 +00:00
lemon_sprintf ( buf , " %s.lt " , lemp - > filename ) ;
2000-05-29 14:26:00 +00:00
}
if ( access ( buf , 004 ) = = 0 ) {
tpltname = buf ;
2001-04-03 16:53:21 +00:00
} else if ( access ( templatename , 004 ) = = 0 ) {
tpltname = templatename ;
2000-05-29 14:26:00 +00:00
} else {
2023-06-08 12:52:28 +00:00
toFree = tpltname = pathsearch ( lemp - > argv [ 0 ] , templatename , 0 ) ;
2000-05-29 14:26:00 +00:00
}
if ( tpltname = = 0 ) {
fprintf ( stderr , " Can't find the parser driver template file \" %s \" . \n " ,
templatename ) ;
lemp - > errorcnt + + ;
return 0 ;
}
2004-09-10 00:14:04 +00:00
in = fopen ( tpltname , " rb " ) ;
2000-05-29 14:26:00 +00:00
if ( in = = 0 ) {
2020-09-20 12:10:28 +00:00
fprintf ( stderr , " Can't open the template file \" %s \" . \n " , tpltname ) ;
2000-05-29 14:26:00 +00:00
lemp - > errorcnt + + ;
}
2020-09-20 12:10:28 +00:00
free ( toFree ) ;
2000-05-29 14:26:00 +00:00
return in ;
}
2004-09-07 11:28:25 +00:00
/* Print a #line directive line to the output file. */
2010-02-14 17:14:22 +00:00
PRIVATE void tplt_linedir ( FILE * out , int lineno , char * filename )
2004-09-07 11:28:25 +00:00
{
fprintf ( out , " #line %d \" " , lineno ) ;
while ( * filename ) {
if ( * filename = = ' \\ ' ) putc ( ' \\ ' , out ) ;
putc ( * filename , out ) ;
filename + + ;
}
fprintf ( out , " \" \n " ) ;
}
2000-05-29 14:26:00 +00:00
/* Print a string to the file and keep the linenumber up to date */
2010-02-14 17:14:22 +00:00
PRIVATE void tplt_print ( FILE * out , struct lemon * lemp , char * str , int * lineno )
2000-05-29 14:26:00 +00:00
{
if ( str = = 0 ) return ;
while ( * str ) {
putc ( * str , out ) ;
2008-12-10 20:10:04 +00:00
if ( * str = = ' \n ' ) ( * lineno ) + + ;
2000-05-29 14:26:00 +00:00
str + + ;
}
2004-09-09 14:01:21 +00:00
if ( str [ - 1 ] ! = ' \n ' ) {
putc ( ' \n ' , out ) ;
( * lineno ) + + ;
}
2008-12-10 20:10:04 +00:00
if ( ! lemp - > nolinenosflag ) {
2017-04-14 19:46:12 +00:00
( * lineno ) + + ; tplt_linedir ( out , * lineno , lemp - > outname ) ;
2008-12-10 20:10:04 +00:00
}
2000-05-29 14:26:00 +00:00
return ;
}
/*
* * The following routine emits code for the destructor for the
* * symbol sp
*/
2010-02-14 17:14:22 +00:00
void emit_destructor_code (
FILE * out ,
struct symbol * sp ,
struct lemon * lemp ,
int * lineno
) {
2004-04-23 23:38:42 +00:00
char * cp = 0 ;
2000-05-29 14:26:00 +00:00
if ( sp - > type = = TERMINAL ) {
cp = lemp - > tokendest ;
if ( cp = = 0 ) return ;
2008-04-27 22:19:44 +00:00
fprintf ( out , " { \n " ) ; ( * lineno ) + + ;
2001-04-03 16:53:21 +00:00
} else if ( sp - > destructor ) {
2000-05-29 14:26:00 +00:00
cp = sp - > destructor ;
2008-04-27 22:19:44 +00:00
fprintf ( out , " { \n " ) ; ( * lineno ) + + ;
2015-09-04 18:03:45 +00:00
if ( ! lemp - > nolinenosflag ) {
( * lineno ) + + ;
tplt_linedir ( out , sp - > destLineno , lemp - > filename ) ;
}
2001-04-03 16:53:21 +00:00
} else if ( lemp - > vardest ) {
cp = lemp - > vardest ;
if ( cp = = 0 ) return ;
2008-04-27 22:19:44 +00:00
fprintf ( out , " { \n " ) ; ( * lineno ) + + ;
2004-04-23 23:38:42 +00:00
} else {
assert ( 0 ) ; /* Cannot happen */
2000-05-29 14:26:00 +00:00
}
for ( ; * cp ; cp + + ) {
if ( * cp = = ' $ ' & & cp [ 1 ] = = ' $ ' ) {
fprintf ( out , " (yypminor->yy%d) " , sp - > dtnum ) ;
cp + + ;
continue ;
}
2008-12-10 20:10:04 +00:00
if ( * cp = = ' \n ' ) ( * lineno ) + + ;
2000-05-29 14:26:00 +00:00
fputc ( * cp , out ) ;
}
2008-12-10 20:10:04 +00:00
fprintf ( out , " \n " ) ; ( * lineno ) + + ;
2017-04-14 19:46:12 +00:00
if ( ! lemp - > nolinenosflag ) {
( * lineno ) + + ; tplt_linedir ( out , * lineno , lemp - > outname ) ;
2008-12-10 20:10:04 +00:00
}
fprintf ( out , " } \n " ) ; ( * lineno ) + + ;
2000-05-29 14:26:00 +00:00
return ;
}
/*
2001-04-03 16:53:21 +00:00
* * Return TRUE ( non - zero ) if the given symbol has a destructor .
2000-05-29 14:26:00 +00:00
*/
2010-02-14 17:14:22 +00:00
int has_destructor ( struct symbol * sp , struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
int ret ;
if ( sp - > type = = TERMINAL ) {
ret = lemp - > tokendest ! = 0 ;
} else {
2001-04-03 16:53:21 +00:00
ret = lemp - > vardest ! = 0 | | sp - > destructor ! = 0 ;
2000-05-29 14:26:00 +00:00
}
return ret ;
}
2004-07-20 14:06:51 +00:00
/*
* * Append text to a dynamically allocated string . If zText is 0 then
* * reset the string to be empty again . Always return the complete text
* * of the string ( which is overwritten with each call ) .
2004-08-19 15:12:26 +00:00
* *
* * n bytes of zText are stored . If n = = 0 then all of zText up to the first
* * \ 000 terminator is stored . zText can contain up to two instances of
* * % d . The values of p1 and p2 are written into the first and second
* * % d .
* *
* * If n = = - 1 , then the previous character is overwritten .
2004-07-20 14:06:51 +00:00
*/
2010-02-14 17:14:22 +00:00
PRIVATE char * append_str ( const char * zText , int n , int p1 , int p2 ) {
static char empty [ 1 ] = { 0 } ;
2004-07-20 14:06:51 +00:00
static char * z = 0 ;
static int alloced = 0 ;
static int used = 0 ;
2004-09-07 11:28:25 +00:00
int c ;
2004-07-20 14:06:51 +00:00
char zInt [ 40 ] ;
if ( zText = = 0 ) {
2016-02-17 01:18:33 +00:00
if ( used = = 0 & & z ! = 0 ) z [ 0 ] = 0 ;
2004-07-20 14:06:51 +00:00
used = 0 ;
return z ;
}
2004-08-19 15:12:26 +00:00
if ( n < = 0 ) {
if ( n < 0 ) {
used + = n ;
assert ( used > = 0 ) ;
}
2008-08-13 20:09:06 +00:00
n = lemonStrlen ( zText ) ;
2004-08-19 15:12:26 +00:00
}
2010-11-23 20:55:27 +00:00
if ( ( int ) ( n + sizeof ( zInt ) * 2 + used ) > = alloced ) {
2004-07-20 14:06:51 +00:00
alloced = n + sizeof ( zInt ) * 2 + used + 200 ;
2010-02-14 17:14:22 +00:00
z = ( char * ) realloc ( z , alloced ) ;
2004-07-20 14:06:51 +00:00
}
2010-02-14 17:14:22 +00:00
if ( z = = 0 ) return empty ;
2004-07-20 14:06:51 +00:00
while ( n - - > 0 ) {
c = * ( zText + + ) ;
2006-10-13 12:25:29 +00:00
if ( c = = ' % ' & & n > 0 & & zText [ 0 ] = = ' d ' ) {
2014-01-10 23:21:00 +00:00
lemon_sprintf ( zInt , " %d " , p1 ) ;
2004-07-20 14:06:51 +00:00
p1 = p2 ;
2014-01-10 23:21:00 +00:00
lemon_strcpy ( & z [ used ] , zInt ) ;
2008-08-13 20:09:06 +00:00
used + = lemonStrlen ( & z [ used ] ) ;
2004-07-20 14:06:51 +00:00
zText + + ;
n - - ;
} else {
2015-01-12 18:02:52 +00:00
z [ used + + ] = ( char ) c ;
2004-07-20 14:06:51 +00:00
}
}
z [ used ] = 0 ;
return z ;
}
/*
2016-05-23 14:24:31 +00:00
* * Write and transform the rp - > code string so that symbols are expanded .
* * Populate the rp - > codePrefix and rp - > codeSuffix strings , as appropriate .
2016-02-17 01:46:19 +00:00
* *
* * Return 1 if the expanded code requires that " yylhsminor " local variable
* * to be defined .
2004-07-20 14:06:51 +00:00
*/
2016-02-17 01:46:19 +00:00
PRIVATE int translate_code ( struct lemon * lemp , struct rule * rp ) {
2004-07-20 14:06:51 +00:00
char * cp , * xp ;
int i ;
2016-02-17 04:33:10 +00:00
int rc = 0 ; /* True if yylhsminor is used */
2016-02-17 12:34:03 +00:00
int dontUseRhs0 = 0 ; /* If true, use of left-most RHS label is illegal */
2016-02-17 04:33:10 +00:00
const char * zSkip = 0 ; /* The zOvwrt comment within rp->code, or NULL */
char lhsused = 0 ; /* True if the LHS element has been used */
char lhsdirect ; /* True if LHS writes directly into stack */
char used [ MAXRHS ] ; /* True for each RHS element which is used */
char zLhs [ 50 ] ; /* Convert the LHS symbol into this string */
char zOvwrt [ 900 ] ; /* Comment that to allow LHS to overwrite RHS */
2004-07-20 14:06:51 +00:00
for ( i = 0 ; i < rp - > nrhs ; i + + ) used [ i ] = 0 ;
lhsused = 0 ;
2007-03-29 20:13:53 +00:00
if ( rp - > code = = 0 ) {
2010-02-14 17:14:22 +00:00
static char newlinestr [ 2 ] = { ' \n ' , ' \0 ' } ;
rp - > code = newlinestr ;
2007-03-29 20:13:53 +00:00
rp - > line = rp - > ruleline ;
2016-05-23 14:24:31 +00:00
rp - > noCode = 1 ;
} else {
rp - > noCode = 0 ;
2007-03-29 20:13:53 +00:00
}
2016-02-17 01:18:33 +00:00
2016-04-30 17:19:30 +00:00
if ( rp - > nrhs = = 0 ) {
2016-02-17 01:18:33 +00:00
/* If there are no RHS symbols, then writing directly to the LHS is ok */
lhsdirect = 1 ;
} else if ( rp - > rhsalias [ 0 ] = = 0 ) {
2016-04-30 17:19:30 +00:00
/* The left-most RHS symbol has no value. LHS direct is ok. But
2021-01-07 16:10:14 +00:00
* * we have to call the destructor on the RHS symbol first . */
2016-02-17 01:18:33 +00:00
lhsdirect = 1 ;
if ( has_destructor ( rp - > rhs [ 0 ] , lemp ) ) {
append_str ( 0 , 0 , 0 , 0 ) ;
append_str ( " yy_destructor(yypParser,%d,&yymsp[%d].minor); \n " , 0 ,
rp - > rhs [ 0 ] - > index , 1 - rp - > nrhs ) ;
rp - > codePrefix = Strsafe ( append_str ( 0 , 0 , 0 , 0 ) ) ;
2016-05-23 14:24:31 +00:00
rp - > noCode = 0 ;
2016-02-17 01:18:33 +00:00
}
2016-04-30 17:19:30 +00:00
} else if ( rp - > lhsalias = = 0 ) {
/* There is no LHS value symbol. */
lhsdirect = 1 ;
2016-02-17 01:18:33 +00:00
} else if ( strcmp ( rp - > lhsalias , rp - > rhsalias [ 0 ] ) = = 0 ) {
2017-04-14 19:46:12 +00:00
/* The LHS symbol and the left-most RHS symbol are the same, so
2016-02-17 01:18:33 +00:00
* * direct writing is allowed */
lhsdirect = 1 ;
lhsused = 1 ;
used [ 0 ] = 1 ;
if ( rp - > lhs - > dtnum ! = rp - > rhs [ 0 ] - > dtnum ) {
ErrorMsg ( lemp - > filename , rp - > ruleline ,
" %s(%s) and %s(%s) share the same label but have "
" different datatypes. " ,
rp - > lhs - > name , rp - > lhsalias , rp - > rhs [ 0 ] - > name , rp - > rhsalias [ 0 ] ) ;
lemp - > errorcnt + + ;
2017-04-14 19:46:12 +00:00
}
2016-02-17 01:18:33 +00:00
} else {
2016-02-17 04:33:10 +00:00
lemon_sprintf ( zOvwrt , " /*%s-overwrites-%s*/ " ,
rp - > lhsalias , rp - > rhsalias [ 0 ] ) ;
zSkip = strstr ( rp - > code , zOvwrt ) ;
if ( zSkip ! = 0 ) {
/* The code contains a special comment that indicates that it is safe
* * for the LHS label to overwrite left - most RHS label . */
lhsdirect = 1 ;
} else {
lhsdirect = 0 ;
}
2016-02-17 01:18:33 +00:00
}
if ( lhsdirect ) {
sprintf ( zLhs , " yymsp[%d].minor.yy%d " , 1 - rp - > nrhs , rp - > lhs - > dtnum ) ;
} else {
2016-02-17 01:46:19 +00:00
rc = 1 ;
2016-02-17 01:18:33 +00:00
sprintf ( zLhs , " yylhsminor.yy%d " , rp - > lhs - > dtnum ) ;
}
2004-07-20 14:06:51 +00:00
append_str ( 0 , 0 , 0 , 0 ) ;
2010-02-14 17:14:22 +00:00
/* This const cast is wrong but harmless, if we're careful. */
for ( cp = ( char * ) rp - > code ; * cp ; cp + + ) {
2016-02-17 04:33:10 +00:00
if ( cp = = zSkip ) {
append_str ( zOvwrt , 0 , 0 , 0 ) ;
cp + = lemonStrlen ( zOvwrt ) - 1 ;
2016-02-17 12:34:03 +00:00
dontUseRhs0 = 1 ;
2016-02-17 04:33:10 +00:00
continue ;
}
2015-10-29 13:48:15 +00:00
if ( ISALPHA ( * cp ) & & ( cp = = rp - > code | | ( ! ISALNUM ( cp [ - 1 ] ) & & cp [ - 1 ] ! = ' _ ' ) ) ) {
2004-07-20 14:06:51 +00:00
char saved ;
2015-10-29 13:48:15 +00:00
for ( xp = & cp [ 1 ] ; ISALNUM ( * xp ) | | * xp = = ' _ ' ; xp + + ) ;
2004-07-20 14:06:51 +00:00
saved = * xp ;
* xp = 0 ;
if ( rp - > lhsalias & & strcmp ( cp , rp - > lhsalias ) = = 0 ) {
2016-02-17 01:18:33 +00:00
append_str ( zLhs , 0 , 0 , 0 ) ;
2004-07-20 14:06:51 +00:00
cp = xp ;
lhsused = 1 ;
} else {
for ( i = 0 ; i < rp - > nrhs ; i + + ) {
if ( rp - > rhsalias [ i ] & & strcmp ( cp , rp - > rhsalias [ i ] ) = = 0 ) {
2016-02-17 12:34:03 +00:00
if ( i = = 0 & & dontUseRhs0 ) {
ErrorMsg ( lemp - > filename , rp - > ruleline ,
" Label %s used after '%s'. " ,
rp - > rhsalias [ 0 ] , zOvwrt ) ;
lemp - > errorcnt + + ;
} else if ( cp ! = rp - > code & & cp [ - 1 ] = = ' @ ' ) {
2004-08-19 15:12:26 +00:00
/* If the argument is of the form @X then substituted
* * the token number of X , not the value of X */
append_str ( " yymsp[%d].major " , - 1 , i - rp - > nrhs + 1 , 0 ) ;
} else {
2005-11-06 04:06:59 +00:00
struct symbol * sp = rp - > rhs [ i ] ;
int dtnum ;
if ( sp - > type = = MULTITERMINAL ) {
dtnum = sp - > subsym [ 0 ] - > dtnum ;
} else {
dtnum = sp - > dtnum ;
}
append_str ( " yymsp[%d].minor.yy%d " , 0 , i - rp - > nrhs + 1 , dtnum ) ;
2004-08-19 15:12:26 +00:00
}
2004-07-20 14:06:51 +00:00
cp = xp ;
used [ i ] = 1 ;
break ;
}
}
}
* xp = saved ;
}
append_str ( cp , 1 , 0 , 0 ) ;
} /* End loop */
2016-02-17 01:18:33 +00:00
/* Main code generation completed */
cp = append_str ( 0 , 0 , 0 , 0 ) ;
if ( cp & & cp [ 0 ] ) rp - > code = Strsafe ( cp ) ;
append_str ( 0 , 0 , 0 , 0 ) ;
2004-07-20 14:06:51 +00:00
/* Check to make sure the LHS has been used */
if ( rp - > lhsalias & & ! lhsused ) {
ErrorMsg ( lemp - > filename , rp - > ruleline ,
" Label \" %s \" for \" %s(%s) \" is never used. " ,
rp - > lhsalias , rp - > lhs - > name , rp - > lhsalias ) ;
lemp - > errorcnt + + ;
}
2016-02-17 01:18:33 +00:00
/* Generate destructor code for RHS minor values which are not referenced.
* * Generate error messages for unused labels and duplicate labels .
*/
2004-07-20 14:06:51 +00:00
for ( i = 0 ; i < rp - > nrhs ; i + + ) {
2016-02-17 01:18:33 +00:00
if ( rp - > rhsalias [ i ] ) {
if ( i > 0 ) {
int j ;
if ( rp - > lhsalias & & strcmp ( rp - > lhsalias , rp - > rhsalias [ i ] ) = = 0 ) {
ErrorMsg ( lemp - > filename , rp - > ruleline ,
" %s(%s) has the same label as the LHS but is not the left-most "
" symbol on the RHS. " ,
2019-04-30 14:26:31 +00:00
rp - > rhs [ i ] - > name , rp - > rhsalias [ i ] ) ;
2016-02-17 01:18:33 +00:00
lemp - > errorcnt + + ;
}
for ( j = 0 ; j < i ; j + + ) {
if ( rp - > rhsalias [ j ] & & strcmp ( rp - > rhsalias [ j ] , rp - > rhsalias [ i ] ) = = 0 ) {
ErrorMsg ( lemp - > filename , rp - > ruleline ,
" Label %s used for multiple symbols on the RHS of a rule. " ,
rp - > rhsalias [ i ] ) ;
lemp - > errorcnt + + ;
break ;
}
}
2004-07-20 14:06:51 +00:00
}
2016-02-17 01:18:33 +00:00
if ( ! used [ i ] ) {
ErrorMsg ( lemp - > filename , rp - > ruleline ,
" Label %s for \" %s(%s) \" is never used. " ,
rp - > rhsalias [ i ] , rp - > rhs [ i ] - > name , rp - > rhsalias [ i ] ) ;
lemp - > errorcnt + + ;
}
} else if ( i > 0 & & has_destructor ( rp - > rhs [ i ] , lemp ) ) {
append_str ( " yy_destructor(yypParser,%d,&yymsp[%d].minor); \n " , 0 ,
rp - > rhs [ i ] - > index , i - rp - > nrhs + 1 ) ;
2004-07-20 14:06:51 +00:00
}
}
2016-02-17 01:18:33 +00:00
/* If unable to write LHS values directly into the stack, write the
* * saved LHS value now . */
if ( lhsdirect = = 0 ) {
append_str ( " yymsp[%d].minor.yy%d = " , 0 , 1 - rp - > nrhs , rp - > lhs - > dtnum ) ;
append_str ( zLhs , 0 , 0 , 0 ) ;
append_str ( " ; \n " , 0 , 0 , 0 ) ;
2007-01-16 03:09:02 +00:00
}
2016-02-17 01:18:33 +00:00
/* Suffix code generation complete */
cp = append_str ( 0 , 0 , 0 , 0 ) ;
2016-05-23 14:24:31 +00:00
if ( cp & & cp [ 0 ] ) {
rp - > codeSuffix = Strsafe ( cp ) ;
rp - > noCode = 0 ;
}
2016-02-17 01:46:19 +00:00
return rc ;
2004-07-20 14:06:51 +00:00
}
2017-04-14 19:46:12 +00:00
/*
2000-05-29 14:26:00 +00:00
* * Generate code which executes when the rule " rp " is reduced . Write
* * the code to " out " . Make sure lineno stays up - to - date .
*/
2010-02-14 17:14:22 +00:00
PRIVATE void emit_code (
FILE * out ,
struct rule * rp ,
struct lemon * lemp ,
int * lineno
) {
const char * cp ;
2000-05-29 14:26:00 +00:00
2016-02-17 01:18:33 +00:00
/* Setup code prior to the #line directive */
if ( rp - > codePrefix & & rp - > codePrefix [ 0 ] ) {
fprintf ( out , " {%s " , rp - > codePrefix ) ;
for ( cp = rp - > codePrefix ; * cp ; cp + + ) { if ( * cp = = ' \n ' ) ( * lineno ) + + ; }
}
2000-05-29 14:26:00 +00:00
/* Generate code to do the reduce action */
if ( rp - > code ) {
2015-09-04 18:03:45 +00:00
if ( ! lemp - > nolinenosflag ) {
( * lineno ) + + ;
tplt_linedir ( out , rp - > line , lemp - > filename ) ;
}
2004-09-07 11:28:25 +00:00
fprintf ( out , " {%s " , rp - > code ) ;
2016-02-17 01:18:33 +00:00
for ( cp = rp - > code ; * cp ; cp + + ) { if ( * cp = = ' \n ' ) ( * lineno ) + + ; }
2008-12-10 20:10:04 +00:00
fprintf ( out , " } \n " ) ; ( * lineno ) + + ;
2015-09-04 18:03:45 +00:00
if ( ! lemp - > nolinenosflag ) {
( * lineno ) + + ;
tplt_linedir ( out , * lineno , lemp - > outname ) ;
}
2016-02-17 01:18:33 +00:00
}
/* Generate breakdown code that occurs after the #line directive */
if ( rp - > codeSuffix & & rp - > codeSuffix [ 0 ] ) {
fprintf ( out , " %s " , rp - > codeSuffix ) ;
for ( cp = rp - > codeSuffix ; * cp ; cp + + ) { if ( * cp = = ' \n ' ) ( * lineno ) + + ; }
}
if ( rp - > codePrefix ) {
fprintf ( out , " } \n " ) ; ( * lineno ) + + ;
}
2000-05-29 14:26:00 +00:00
return ;
}
/*
* * Print the definition of the union used for the parser ' s data stack .
* * This union contains fields for every possible data type for tokens
* * and nonterminals . In the process of computing and printing this
* * union , also set the " .dtnum " field of every terminal and nonterminal
* * symbol .
*/
2010-02-14 17:14:22 +00:00
void print_stack_union (
FILE * out , /* The output stream */
struct lemon * lemp , /* The main info structure for this parser */
int * plineno , /* Pointer to the line number */
int mhflag /* True if generating makeheaders output */
) {
2021-10-04 16:14:51 +00:00
int lineno ; /* The line number of the output */
2000-05-29 14:26:00 +00:00
char * * types ; /* A hash table of datatypes */
int arraysize ; /* Size of the "types" array */
int maxdtlength ; /* Maximum length of any ".datatype" field. */
char * stddt ; /* Standardized name for a datatype */
int i , j ; /* Loop counters */
2013-10-02 20:46:30 +00:00
unsigned hash ; /* For hashing the name of a type */
2010-02-14 17:14:22 +00:00
const char * name ; /* Name of the parser */
2000-05-29 14:26:00 +00:00
/* Allocate and initialize types[] and allocate stddt[] */
arraysize = lemp - > nsymbol * 2 ;
2007-12-21 00:02:11 +00:00
types = ( char * * ) calloc ( arraysize , sizeof ( char * ) ) ;
2011-06-02 15:48:51 +00:00
if ( types = = 0 ) {
fprintf ( stderr , " Out of memory. \n " ) ;
exit ( 1 ) ;
}
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < arraysize ; i + + ) types [ i ] = 0 ;
maxdtlength = 0 ;
2001-04-03 16:53:21 +00:00
if ( lemp - > vartype ) {
2008-08-13 20:09:06 +00:00
maxdtlength = lemonStrlen ( lemp - > vartype ) ;
2001-04-03 16:53:21 +00:00
}
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
int len ;
struct symbol * sp = lemp - > symbols [ i ] ;
if ( sp - > datatype = = 0 ) continue ;
2008-08-13 20:09:06 +00:00
len = lemonStrlen ( sp - > datatype ) ;
2000-05-29 14:26:00 +00:00
if ( len > maxdtlength ) maxdtlength = len ;
}
stddt = ( char * ) malloc ( maxdtlength * 2 + 1 ) ;
2011-06-02 15:48:51 +00:00
if ( stddt = = 0 ) {
2000-05-29 14:26:00 +00:00
fprintf ( stderr , " Out of memory. \n " ) ;
exit ( 1 ) ;
}
/* Build a hash table of datatypes. The ".dtnum" field of each symbol
* * is filled in with the hash index plus 1. A " .dtnum " value of 0 is
2001-04-03 16:53:21 +00:00
* * used for terminal symbols . If there is no % default_type defined then
* * 0 is also used as the . dtnum value for nonterminals which do not specify
* * a datatype using the % type directive .
*/
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
struct symbol * sp = lemp - > symbols [ i ] ;
char * cp ;
if ( sp = = lemp - > errsym ) {
sp - > dtnum = arraysize + 1 ;
continue ;
}
2001-04-03 16:53:21 +00:00
if ( sp - > type ! = NONTERMINAL | | ( sp - > datatype = = 0 & & lemp - > vartype = = 0 ) ) {
2000-05-29 14:26:00 +00:00
sp - > dtnum = 0 ;
continue ;
}
cp = sp - > datatype ;
2001-04-03 16:53:21 +00:00
if ( cp = = 0 ) cp = lemp - > vartype ;
2000-05-29 14:26:00 +00:00
j = 0 ;
2015-10-29 13:48:15 +00:00
while ( ISSPACE ( * cp ) ) cp + + ;
2000-05-29 14:26:00 +00:00
while ( * cp ) stddt [ j + + ] = * cp + + ;
2015-10-29 13:48:15 +00:00
while ( j > 0 & & ISSPACE ( stddt [ j - 1 ] ) ) j - - ;
2000-05-29 14:26:00 +00:00
stddt [ j ] = 0 ;
2009-04-05 15:18:02 +00:00
if ( lemp - > tokentype & & strcmp ( stddt , lemp - > tokentype ) = = 0 ) {
2008-07-01 16:34:49 +00:00
sp - > dtnum = 0 ;
continue ;
}
2000-05-29 14:26:00 +00:00
hash = 0 ;
for ( j = 0 ; stddt [ j ] ; j + + ) {
hash = hash * 53 + stddt [ j ] ;
}
2003-05-13 00:34:21 +00:00
hash = ( hash & 0x7fffffff ) % arraysize ;
2000-05-29 14:26:00 +00:00
while ( types [ hash ] ) {
if ( strcmp ( types [ hash ] , stddt ) = = 0 ) {
sp - > dtnum = hash + 1 ;
break ;
}
hash + + ;
2013-10-11 23:01:02 +00:00
if ( hash > = ( unsigned ) arraysize ) hash = 0 ;
2000-05-29 14:26:00 +00:00
}
if ( types [ hash ] = = 0 ) {
sp - > dtnum = hash + 1 ;
2008-08-13 20:09:06 +00:00
types [ hash ] = ( char * ) malloc ( lemonStrlen ( stddt ) + 1 ) ;
2000-05-29 14:26:00 +00:00
if ( types [ hash ] = = 0 ) {
fprintf ( stderr , " Out of memory. \n " ) ;
exit ( 1 ) ;
}
2014-01-10 23:21:00 +00:00
lemon_strcpy ( types [ hash ] , stddt ) ;
2000-05-29 14:26:00 +00:00
}
}
/* Print out the definition of YYTOKENTYPE and YYMINORTYPE */
name = lemp - > name ? lemp - > name : " Parse " ;
lineno = * plineno ;
if ( mhflag ) { fprintf ( out , " #if INTERFACE \n " ) ; lineno + + ; }
fprintf ( out , " #define %sTOKENTYPE %s \n " , name ,
lemp - > tokentype ? lemp - > tokentype : " void* " ) ; lineno + + ;
if ( mhflag ) { fprintf ( out , " #endif \n " ) ; lineno + + ; }
fprintf ( out , " typedef union { \n " ) ; lineno + + ;
2008-12-11 02:20:43 +00:00
fprintf ( out , " int yyinit; \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
fprintf ( out , " %sTOKENTYPE yy0; \n " , name ) ; lineno + + ;
for ( i = 0 ; i < arraysize ; i + + ) {
if ( types [ i ] = = 0 ) continue ;
fprintf ( out , " %s yy%d; \n " , types [ i ] , i + 1 ) ; lineno + + ;
free ( types [ i ] ) ;
}
2018-04-16 14:31:34 +00:00
if ( lemp - > errsym & & lemp - > errsym - > useCnt ) {
2008-01-22 01:48:05 +00:00
fprintf ( out , " int yy%d; \n " , lemp - > errsym - > dtnum ) ; lineno + + ;
}
2000-05-29 14:26:00 +00:00
free ( stddt ) ;
free ( types ) ;
fprintf ( out , " } YYMINORTYPE; \n " ) ; lineno + + ;
* plineno = lineno ;
}
2002-02-23 19:39:46 +00:00
/*
* * Return the name of a C datatype able to represent values between
2015-09-07 02:23:02 +00:00
* * lwr and upr , inclusive . If pnByte ! = NULL then also write the sizeof
* * for that type ( 1 , 2 , or 4 ) into * pnByte .
2002-02-23 19:39:46 +00:00
*/
2015-09-07 02:23:02 +00:00
static const char * minimum_size_type ( int lwr , int upr , int * pnByte ) {
const char * zType = " int " ;
int nByte = 4 ;
2003-10-21 13:16:03 +00:00
if ( lwr > = 0 ) {
if ( upr < = 255 ) {
2015-09-07 02:23:02 +00:00
zType = " unsigned char " ;
nByte = 1 ;
2003-10-21 13:16:03 +00:00
} else if ( upr < 65535 ) {
2015-09-07 02:23:02 +00:00
zType = " unsigned short int " ;
nByte = 2 ;
2003-10-21 13:16:03 +00:00
} else {
2015-09-07 02:23:02 +00:00
zType = " unsigned int " ;
nByte = 4 ;
2003-10-21 13:16:03 +00:00
}
} else if ( lwr > = - 127 & & upr < = 127 ) {
2015-09-07 02:23:02 +00:00
zType = " signed char " ;
nByte = 1 ;
2003-10-21 13:16:03 +00:00
} else if ( lwr > = - 32767 & & upr < 32767 ) {
2015-09-07 02:23:02 +00:00
zType = " short " ;
nByte = 2 ;
2002-02-23 19:39:46 +00:00
}
2015-09-07 02:23:02 +00:00
if ( pnByte ) * pnByte = nByte ;
return zType ;
2002-02-23 19:39:46 +00:00
}
2003-10-21 16:34:41 +00:00
/*
* * Each state contains a set of token transaction and a set of
* * nonterminal transactions . Each of these sets makes an instance
* * of the following structure . An array of these structures is used
* * to order the creation of entries in the yy_action [ ] table .
*/
struct axset {
struct state * stp ; /* A pointer to a state */
int isTkn ; /* True to use tokens. False for non-terminals */
int nAction ; /* Number of actions */
2009-11-03 13:02:25 +00:00
int iOrder ; /* Original order of action sets */
2003-10-21 16:34:41 +00:00
} ;
/*
* * Compare to axset structures for sorting purposes
*/
static int axset_compare ( const void * a , const void * b ) {
struct axset * p1 = ( struct axset * ) a ;
struct axset * p2 = ( struct axset * ) b ;
2009-11-03 13:02:25 +00:00
int c ;
c = p2 - > nAction - p1 - > nAction ;
if ( c = = 0 ) {
2015-09-07 23:40:42 +00:00
c = p1 - > iOrder - p2 - > iOrder ;
2009-11-03 13:02:25 +00:00
}
assert ( c ! = 0 | | p1 = = p2 ) ;
return c ;
2003-10-21 16:34:41 +00:00
}
2008-01-22 01:48:05 +00:00
/*
* * Write text on " out " that describes the rule " rp " .
*/
static void writeRuleText ( FILE * out , struct rule * rp ) {
int j ;
fprintf ( out , " %s ::= " , rp - > lhs - > name ) ;
for ( j = 0 ; j < rp - > nrhs ; j + + ) {
struct symbol * sp = rp - > rhs [ j ] ;
2014-01-11 03:06:18 +00:00
if ( sp - > type ! = MULTITERMINAL ) {
fprintf ( out , " %s " , sp - > name ) ;
} else {
2008-01-22 01:48:05 +00:00
int k ;
2014-01-11 03:06:18 +00:00
fprintf ( out , " %s " , sp - > subsym [ 0 ] - > name ) ;
2008-01-22 01:48:05 +00:00
for ( k = 1 ; k < sp - > nsubsym ; k + + ) {
fprintf ( out , " |%s " , sp - > subsym [ k ] - > name ) ;
}
}
}
}
2000-05-29 14:26:00 +00:00
/* Generate C source code for the parser */
2010-02-14 17:14:22 +00:00
void ReportTable (
struct lemon * lemp ,
2019-11-26 02:22:39 +00:00
int mhflag , /* Output in makeheaders format if true */
int sqlFlag /* Generate the *.sql file too */
2010-02-14 17:14:22 +00:00
) {
2019-11-26 02:22:39 +00:00
FILE * out , * in , * sql ;
2000-05-29 14:26:00 +00:00
int lineno ;
struct state * stp ;
struct action * ap ;
struct rule * rp ;
2003-10-21 13:16:03 +00:00
struct acttab * pActtab ;
2015-09-07 02:23:02 +00:00
int i , j , n , sz ;
2019-08-28 02:09:47 +00:00
int nLookAhead ;
2015-09-07 02:23:02 +00:00
int szActionType ; /* sizeof(YYACTIONTYPE) */
int szCodeType ; /* sizeof(YYCODETYPE) */
2010-02-14 17:14:22 +00:00
const char * name ;
2003-10-21 13:16:03 +00:00
int mnTknOfst , mxTknOfst ;
int mnNtOfst , mxNtOfst ;
2003-10-21 16:34:41 +00:00
struct axset * ax ;
2020-09-01 11:20:03 +00:00
char * prefix ;
2000-05-29 14:26:00 +00:00
2017-12-24 23:38:10 +00:00
lemp - > minShiftReduce = lemp - > nstate ;
lemp - > errAction = lemp - > minShiftReduce + lemp - > nrule ;
lemp - > accAction = lemp - > errAction + 1 ;
lemp - > noAction = lemp - > accAction + 1 ;
lemp - > minReduce = lemp - > noAction + 1 ;
lemp - > maxAction = lemp - > minReduce + lemp - > nrule ;
2000-05-29 14:26:00 +00:00
in = tplt_open ( lemp ) ;
if ( in = = 0 ) return ;
2004-09-10 00:14:04 +00:00
out = file_open ( lemp , " .c " , " wb " ) ;
2000-05-29 14:26:00 +00:00
if ( out = = 0 ) {
fclose ( in ) ;
return ;
}
2019-11-26 02:22:39 +00:00
if ( sqlFlag = = 0 ) {
sql = 0 ;
} else {
sql = file_open ( lemp , " .sql " , " wb " ) ;
if ( sql = = 0 ) {
fclose ( in ) ;
fclose ( out ) ;
return ;
}
fprintf ( sql ,
2019-11-29 12:51:00 +00:00
" BEGIN; \n "
2019-11-26 02:22:39 +00:00
" CREATE TABLE symbol( \n "
" id INTEGER PRIMARY KEY, \n "
" name TEXT NOT NULL, \n "
" isTerminal BOOLEAN NOT NULL, \n "
2019-11-29 12:51:00 +00:00
" fallback INTEGER REFERENCES symbol "
" DEFERRABLE INITIALLY DEFERRED \n "
2019-11-26 02:22:39 +00:00
" ); \n "
) ;
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
fprintf ( sql ,
" INSERT INTO symbol(id,name,isTerminal,fallback) "
" VALUES(%d,'%s',%s " ,
i , lemp - > symbols [ i ] - > name ,
i < lemp - > nterminal ? " TRUE " : " FALSE "
) ;
if ( lemp - > symbols [ i ] - > fallback ) {
fprintf ( sql , " ,%d); \n " , lemp - > symbols [ i ] - > fallback - > index ) ;
} else {
fprintf ( sql , " ,NULL); \n " ) ;
}
}
fprintf ( sql ,
" CREATE TABLE rule( \n "
" ruleid INTEGER PRIMARY KEY, \n "
2019-12-19 12:29:31 +00:00
" lhs INTEGER REFERENCES symbol(id), \n "
" txt TEXT \n "
2019-11-26 02:22:39 +00:00
" ); \n "
" CREATE TABLE rulerhs( \n "
" ruleid INTEGER REFERENCES rule(ruleid), \n "
" pos INTEGER, \n "
" sym INTEGER REFERENCES symbol(id) \n "
" ); \n "
) ;
for ( i = 0 , rp = lemp - > rule ; rp ; rp = rp - > next , i + + ) {
assert ( i = = rp - > iRule ) ;
fprintf ( sql ,
2019-12-19 13:17:07 +00:00
" INSERT INTO rule(ruleid,lhs,txt)VALUES(%d,%d,' " ,
2019-11-26 02:22:39 +00:00
rp - > iRule , rp - > lhs - > index
) ;
2019-12-19 12:29:31 +00:00
writeRuleText ( sql , rp ) ;
fprintf ( sql , " '); \n " ) ;
2019-11-26 02:22:39 +00:00
for ( j = 0 ; j < rp - > nrhs ; j + + ) {
struct symbol * sp = rp - > rhs [ j ] ;
if ( sp - > type ! = MULTITERMINAL ) {
fprintf ( sql ,
" INSERT INTO rulerhs(ruleid,pos,sym)VALUES(%d,%d,%d); \n " ,
i , j , sp - > index
) ;
} else {
int k ;
for ( k = 0 ; k < sp - > nsubsym ; k + + ) {
fprintf ( sql ,
" INSERT INTO rulerhs(ruleid,pos,sym)VALUES(%d,%d,%d); \n " ,
i , j , sp - > subsym [ k ] - > index
) ;
}
}
}
}
2019-11-29 12:51:00 +00:00
fprintf ( sql , " COMMIT; \n " ) ;
2019-11-26 02:22:39 +00:00
}
2000-05-29 14:26:00 +00:00
lineno = 1 ;
2020-09-01 11:20:03 +00:00
2020-09-01 12:26:55 +00:00
fprintf ( out ,
" /* This file is automatically generated by Lemon from input grammar \n "
2023-06-08 12:52:28 +00:00
" ** source file \" %s \" " , lemp - > filename ) ; lineno + + ;
if ( nDefineUsed = = 0 ) {
fprintf ( out , " . \n */ \n " ) ; lineno + = 2 ;
} else {
fprintf ( out , " with these options: \n ** \n " ) ; lineno + = 2 ;
for ( i = 0 ; i < nDefine ; i + + ) {
if ( ! bDefineUsed [ i ] ) continue ;
fprintf ( out , " ** -D%s \n " , azDefine [ i ] ) ; lineno + + ;
}
fprintf ( out , " */ \n " ) ; lineno + + ;
}
2020-09-01 12:26:55 +00:00
2020-09-01 11:20:03 +00:00
/* The first %include directive begins with a C-language comment,
* * then skip over the header comment of the template file
*/
if ( lemp - > include = = 0 ) lemp - > include = " " ;
for ( i = 0 ; ISSPACE ( lemp - > include [ i ] ) ; i + + ) {
if ( lemp - > include [ i ] = = ' \n ' ) {
lemp - > include + = i + 1 ;
i = - 1 ;
}
}
if ( lemp - > include [ 0 ] = = ' / ' ) {
tplt_skip_header ( in , & lineno ) ;
} else {
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
}
2000-05-29 14:26:00 +00:00
/* Generate the include code, if any */
2008-04-27 22:19:44 +00:00
tplt_print ( out , lemp , lemp - > include , & lineno ) ;
2000-05-29 14:26:00 +00:00
if ( mhflag ) {
2015-04-19 21:43:16 +00:00
char * incName = file_makename ( lemp , " .h " ) ;
fprintf ( out , " #include \" %s \" \n " , incName ) ; lineno + + ;
free ( incName ) ;
2000-05-29 14:26:00 +00:00
}
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Generate #defines for all tokens */
2020-09-01 11:20:03 +00:00
if ( lemp - > tokenprefix ) prefix = lemp - > tokenprefix ;
else prefix = " " ;
2000-05-29 14:26:00 +00:00
if ( mhflag ) {
fprintf ( out , " #if INTERFACE \n " ) ; lineno + + ;
2020-09-01 11:20:03 +00:00
} else {
fprintf ( out , " #ifndef %s%s \n " , prefix , lemp - > symbols [ 1 ] - > name ) ;
}
for ( i = 1 ; i < lemp - > nterminal ; i + + ) {
fprintf ( out , " #define %s%-30s %2d \n " , prefix , lemp - > symbols [ i ] - > name , i ) ;
lineno + + ;
2000-05-29 14:26:00 +00:00
}
2020-09-01 11:20:03 +00:00
fprintf ( out , " #endif \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Generate the defines */
fprintf ( out , " #define YYCODETYPE %s \n " ,
2018-04-16 14:31:34 +00:00
minimum_size_type ( 0 , lemp - > nsymbol , & szCodeType ) ) ; lineno + + ;
fprintf ( out , " #define YYNOCODE %d \n " , lemp - > nsymbol ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
fprintf ( out , " #define YYACTIONTYPE %s \n " ,
2017-12-24 23:38:10 +00:00
minimum_size_type ( 0 , lemp - > maxAction , & szActionType ) ) ; lineno + + ;
2006-06-10 13:29:31 +00:00
if ( lemp - > wildcard ) {
fprintf ( out , " #define YYWILDCARD %d \n " ,
lemp - > wildcard - > index ) ; lineno + + ;
}
2000-05-29 14:26:00 +00:00
print_stack_union ( out , lemp , & lineno , mhflag ) ;
2007-02-22 23:06:58 +00:00
fprintf ( out , " #ifndef YYSTACKDEPTH \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
if ( lemp - > stacksize ) {
fprintf ( out , " #define YYSTACKDEPTH %s \n " , lemp - > stacksize ) ; lineno + + ;
} else {
fprintf ( out , " #define YYSTACKDEPTH 100 \n " ) ; lineno + + ;
}
2007-02-22 23:06:58 +00:00
fprintf ( out , " #endif \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
if ( mhflag ) {
fprintf ( out , " #if INTERFACE \n " ) ; lineno + + ;
}
name = lemp - > name ? lemp - > name : " Parse " ;
if ( lemp - > arg & & lemp - > arg [ 0 ] ) {
2008-08-13 20:09:06 +00:00
i = lemonStrlen ( lemp - > arg ) ;
2015-10-29 13:48:15 +00:00
while ( i > = 1 & & ISSPACE ( lemp - > arg [ i - 1 ] ) ) i - - ;
while ( i > = 1 & & ( ISALNUM ( lemp - > arg [ i - 1 ] ) | | lemp - > arg [ i - 1 ] = = ' _ ' ) ) i - - ;
2002-03-11 13:55:50 +00:00
fprintf ( out , " #define %sARG_SDECL %s; \n " , name , lemp - > arg ) ; lineno + + ;
fprintf ( out , " #define %sARG_PDECL ,%s \n " , name , lemp - > arg ) ; lineno + + ;
2018-04-21 13:51:42 +00:00
fprintf ( out , " #define %sARG_PARAM ,%s \n " , name , & lemp - > arg [ i ] ) ; lineno + + ;
fprintf ( out , " #define %sARG_FETCH %s=yypParser->%s; \n " ,
2002-03-11 13:55:50 +00:00
name , lemp - > arg , & lemp - > arg [ i ] ) ; lineno + + ;
2018-04-21 13:51:42 +00:00
fprintf ( out , " #define %sARG_STORE yypParser->%s=%s; \n " ,
2002-03-11 13:55:50 +00:00
name , & lemp - > arg [ i ] , & lemp - > arg [ i ] ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
} else {
2018-04-21 13:51:42 +00:00
fprintf ( out , " #define %sARG_SDECL \n " , name ) ; lineno + + ;
fprintf ( out , " #define %sARG_PDECL \n " , name ) ; lineno + + ;
fprintf ( out , " #define %sARG_PARAM \n " , name ) ; lineno + + ;
2002-03-11 13:55:50 +00:00
fprintf ( out , " #define %sARG_FETCH \n " , name ) ; lineno + + ;
fprintf ( out , " #define %sARG_STORE \n " , name ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
}
2018-04-21 13:51:42 +00:00
if ( lemp - > ctx & & lemp - > ctx [ 0 ] ) {
i = lemonStrlen ( lemp - > ctx ) ;
while ( i > = 1 & & ISSPACE ( lemp - > ctx [ i - 1 ] ) ) i - - ;
while ( i > = 1 & & ( ISALNUM ( lemp - > ctx [ i - 1 ] ) | | lemp - > ctx [ i - 1 ] = = ' _ ' ) ) i - - ;
fprintf ( out , " #define %sCTX_SDECL %s; \n " , name , lemp - > ctx ) ; lineno + + ;
fprintf ( out , " #define %sCTX_PDECL ,%s \n " , name , lemp - > ctx ) ; lineno + + ;
fprintf ( out , " #define %sCTX_PARAM ,%s \n " , name , & lemp - > ctx [ i ] ) ; lineno + + ;
fprintf ( out , " #define %sCTX_FETCH %s=yypParser->%s; \n " ,
name , lemp - > ctx , & lemp - > ctx [ i ] ) ; lineno + + ;
fprintf ( out , " #define %sCTX_STORE yypParser->%s=%s; \n " ,
name , & lemp - > ctx [ i ] , & lemp - > ctx [ i ] ) ; lineno + + ;
} else {
fprintf ( out , " #define %sCTX_SDECL \n " , name ) ; lineno + + ;
fprintf ( out , " #define %sCTX_PDECL \n " , name ) ; lineno + + ;
fprintf ( out , " #define %sCTX_PARAM \n " , name ) ; lineno + + ;
fprintf ( out , " #define %sCTX_FETCH \n " , name ) ; lineno + + ;
fprintf ( out , " #define %sCTX_STORE \n " , name ) ; lineno + + ;
}
2000-05-29 14:26:00 +00:00
if ( mhflag ) {
fprintf ( out , " #endif \n " ) ; lineno + + ;
}
2018-04-16 14:31:34 +00:00
if ( lemp - > errsym & & lemp - > errsym - > useCnt ) {
2015-09-07 18:23:37 +00:00
fprintf ( out , " #define YYERRORSYMBOL %d \n " , lemp - > errsym - > index ) ; lineno + + ;
fprintf ( out , " #define YYERRSYMDT yy%d \n " , lemp - > errsym - > dtnum ) ; lineno + + ;
2008-01-22 01:48:05 +00:00
}
2002-06-06 18:54:39 +00:00
if ( lemp - > has_fallback ) {
fprintf ( out , " #define YYFALLBACK 1 \n " ) ; lineno + + ;
}
2000-05-29 14:26:00 +00:00
2015-09-07 18:23:37 +00:00
/* Compute the action table, but do not output it yet. The action
* * table must be computed before generating the YYNSTATE macro because
* * we need to know how many states can be eliminated .
2000-05-29 14:26:00 +00:00
*/
2015-09-07 18:23:37 +00:00
ax = ( struct axset * ) calloc ( lemp - > nxstate * 2 , sizeof ( ax [ 0 ] ) ) ;
2003-10-21 16:34:41 +00:00
if ( ax = = 0 ) {
fprintf ( stderr , " malloc failed \n " ) ;
exit ( 1 ) ;
}
2015-09-07 18:23:37 +00:00
for ( i = 0 ; i < lemp - > nxstate ; i + + ) {
2000-05-29 14:26:00 +00:00
stp = lemp - > sorted [ i ] ;
2003-10-21 16:34:41 +00:00
ax [ i * 2 ] . stp = stp ;
ax [ i * 2 ] . isTkn = 1 ;
ax [ i * 2 ] . nAction = stp - > nTknAct ;
ax [ i * 2 + 1 ] . stp = stp ;
ax [ i * 2 + 1 ] . isTkn = 0 ;
ax [ i * 2 + 1 ] . nAction = stp - > nNtAct ;
2003-10-21 13:16:03 +00:00
}
mxTknOfst = mnTknOfst = 0 ;
mxNtOfst = mnNtOfst = 0 ;
2015-09-07 18:23:37 +00:00
/* In an effort to minimize the action table size, use the heuristic
* * of placing the largest action sets first */
for ( i = 0 ; i < lemp - > nxstate * 2 ; i + + ) ax [ i ] . iOrder = i ;
qsort ( ax , lemp - > nxstate * 2 , sizeof ( ax [ 0 ] ) , axset_compare ) ;
2017-12-25 04:15:38 +00:00
pActtab = acttab_alloc ( lemp - > nsymbol , lemp - > nterminal ) ;
2015-09-07 18:23:37 +00:00
for ( i = 0 ; i < lemp - > nxstate * 2 & & ax [ i ] . nAction > 0 ; i + + ) {
2003-10-21 16:34:41 +00:00
stp = ax [ i ] . stp ;
if ( ax [ i ] . isTkn ) {
for ( ap = stp - > ap ; ap ; ap = ap - > next ) {
int action ;
if ( ap - > sp - > index > = lemp - > nterminal ) continue ;
action = compute_action ( lemp , ap ) ;
if ( action < 0 ) continue ;
acttab_action ( pActtab , ap - > sp - > index , action ) ;
2003-10-21 13:16:03 +00:00
}
2017-12-25 04:15:38 +00:00
stp - > iTknOfst = acttab_insert ( pActtab , 1 ) ;
2003-10-21 16:34:41 +00:00
if ( stp - > iTknOfst < mnTknOfst ) mnTknOfst = stp - > iTknOfst ;
if ( stp - > iTknOfst > mxTknOfst ) mxTknOfst = stp - > iTknOfst ;
} else {
for ( ap = stp - > ap ; ap ; ap = ap - > next ) {
int action ;
if ( ap - > sp - > index < lemp - > nterminal ) continue ;
if ( ap - > sp - > index = = lemp - > nsymbol ) continue ;
action = compute_action ( lemp , ap ) ;
if ( action < 0 ) continue ;
acttab_action ( pActtab , ap - > sp - > index , action ) ;
2000-05-29 14:26:00 +00:00
}
2017-12-25 04:15:38 +00:00
stp - > iNtOfst = acttab_insert ( pActtab , 0 ) ;
2003-10-21 16:34:41 +00:00
if ( stp - > iNtOfst < mnNtOfst ) mnNtOfst = stp - > iNtOfst ;
if ( stp - > iNtOfst > mxNtOfst ) mxNtOfst = stp - > iNtOfst ;
2000-05-29 14:26:00 +00:00
}
2015-09-07 23:40:42 +00:00
#if 0 /* Uncomment for a trace of how the yy_action[] table fills out */
{ int jj , nn ;
for ( jj = nn = 0 ; jj < pActtab - > nAction ; jj + + ) {
if ( pActtab - > aAction [ jj ] . action < 0 ) nn + + ;
}
printf ( " %4d: State %3d %s n: %2d size: %5d freespace: %d \n " ,
i , stp - > statenum , ax [ i ] . isTkn ? " Token " : " Var " ,
ax [ i ] . nAction , pActtab - > nAction , nn ) ;
}
# endif
2003-10-21 13:16:03 +00:00
}
2003-10-21 16:34:41 +00:00
free ( ax ) ;
2000-05-29 14:26:00 +00:00
2016-05-24 18:55:08 +00:00
/* Mark rules that are actually used for reduce actions after all
* * optimizations have been applied
*/
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) rp - > doesReduce = LEMON_FALSE ;
for ( i = 0 ; i < lemp - > nxstate ; i + + ) {
for ( ap = lemp - > sorted [ i ] - > ap ; ap ; ap = ap - > next ) {
if ( ap - > type = = REDUCE | | ap - > type = = SHIFTREDUCE ) {
2017-04-26 04:32:17 +00:00
ap - > x . rp - > doesReduce = 1 ;
2016-05-24 18:55:08 +00:00
}
}
}
2015-09-07 18:23:37 +00:00
/* Finish rendering the constants now that the action table has
* * been computed */
fprintf ( out , " #define YYNSTATE %d \n " , lemp - > nxstate ) ; lineno + + ;
fprintf ( out , " #define YYNRULE %d \n " , lemp - > nrule ) ; lineno + + ;
2019-12-11 18:53:51 +00:00
fprintf ( out , " #define YYNRULE_WITH_ACTION %d \n " , lemp - > nruleWithAction ) ;
lineno + + ;
2017-12-26 18:04:23 +00:00
fprintf ( out , " #define YYNTOKEN %d \n " , lemp - > nterminal ) ; lineno + + ;
2015-09-07 23:40:42 +00:00
fprintf ( out , " #define YY_MAX_SHIFT %d \n " , lemp - > nxstate - 1 ) ; lineno + + ;
2017-12-24 23:38:10 +00:00
i = lemp - > minShiftReduce ;
fprintf ( out , " #define YY_MIN_SHIFTREDUCE %d \n " , i ) ; lineno + + ;
i + = lemp - > nrule ;
2015-09-07 18:23:37 +00:00
fprintf ( out , " #define YY_MAX_SHIFTREDUCE %d \n " , i - 1 ) ; lineno + + ;
2017-12-24 23:38:10 +00:00
fprintf ( out , " #define YY_ERROR_ACTION %d \n " , lemp - > errAction ) ; lineno + + ;
fprintf ( out , " #define YY_ACCEPT_ACTION %d \n " , lemp - > accAction ) ; lineno + + ;
fprintf ( out , " #define YY_NO_ACTION %d \n " , lemp - > noAction ) ; lineno + + ;
fprintf ( out , " #define YY_MIN_REDUCE %d \n " , lemp - > minReduce ) ; lineno + + ;
i = lemp - > minReduce + lemp - > nrule ;
2015-09-07 18:23:37 +00:00
fprintf ( out , " #define YY_MAX_REDUCE %d \n " , i - 1 ) ; lineno + + ;
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Now output the action table and its associates:
* *
* * yy_action [ ] A single table containing all actions .
* * yy_lookahead [ ] A table containing the lookahead for each entry in
* * yy_action . Used to detect hash collisions .
* * yy_shift_ofst [ ] For each state , the offset into yy_action for
* * shifting terminals .
* * yy_reduce_ofst [ ] For each state , the offset into yy_action for
* * shifting non - terminals after a reduce .
* * yy_default [ ] Default action for each state .
*/
2003-10-21 13:16:03 +00:00
/* Output the yy_action table */
2017-12-25 04:15:38 +00:00
lemp - > nactiontab = n = acttab_action_size ( pActtab ) ;
2015-09-07 02:23:02 +00:00
lemp - > tablesize + = n * szActionType ;
2009-11-03 19:18:31 +00:00
fprintf ( out , " #define YY_ACTTAB_COUNT (%d) \n " , n ) ; lineno + + ;
fprintf ( out , " static const YYACTIONTYPE yy_action[] = { \n " ) ; lineno + + ;
2003-10-21 13:16:03 +00:00
for ( i = j = 0 ; i < n ; i + + ) {
int action = acttab_yyaction ( pActtab , i ) ;
2017-12-24 23:38:10 +00:00
if ( action < 0 ) action = lemp - > noAction ;
2003-10-21 16:34:41 +00:00
if ( j = = 0 ) fprintf ( out , " /* %5d */ " , i ) ;
2003-10-21 13:16:03 +00:00
fprintf ( out , " %4d, " , action ) ;
if ( j = = 9 | | i = = n - 1 ) {
fprintf ( out , " \n " ) ; lineno + + ;
j = 0 ;
} else {
j + + ;
2000-05-29 14:26:00 +00:00
}
2003-10-21 13:16:03 +00:00
}
fprintf ( out , " }; \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
2003-10-21 13:16:03 +00:00
/* Output the yy_lookahead table */
2017-12-25 04:15:38 +00:00
lemp - > nlookaheadtab = n = acttab_lookahead_size ( pActtab ) ;
2015-09-07 02:23:02 +00:00
lemp - > tablesize + = n * szCodeType ;
2004-10-06 15:41:16 +00:00
fprintf ( out , " static const YYCODETYPE yy_lookahead[] = { \n " ) ; lineno + + ;
2003-10-21 13:16:03 +00:00
for ( i = j = 0 ; i < n ; i + + ) {
int la = acttab_yylookahead ( pActtab , i ) ;
if ( la < 0 ) la = lemp - > nsymbol ;
2003-10-21 16:34:41 +00:00
if ( j = = 0 ) fprintf ( out , " /* %5d */ " , i ) ;
2003-10-21 13:16:03 +00:00
fprintf ( out , " %4d, " , la ) ;
2019-08-28 02:09:47 +00:00
if ( j = = 9 ) {
fprintf ( out , " \n " ) ; lineno + + ;
j = 0 ;
} else {
j + + ;
}
}
/* Add extra entries to the end of the yy_lookahead[] table so that
* * yy_shift_ofst [ ] + iToken will always be a valid index into the array ,
* * even for the largest possible value of yy_shift_ofst [ ] and iToken . */
nLookAhead = lemp - > nterminal + lemp - > nactiontab ;
while ( i < nLookAhead ) {
if ( j = = 0 ) fprintf ( out , " /* %5d */ " , i ) ;
fprintf ( out , " %4d, " , lemp - > nterminal ) ;
if ( j = = 9 ) {
2003-10-21 13:16:03 +00:00
fprintf ( out , " \n " ) ; lineno + + ;
j = 0 ;
} else {
j + + ;
2002-03-03 02:49:51 +00:00
}
2019-08-28 02:09:47 +00:00
i + + ;
2003-10-21 13:16:03 +00:00
}
2019-09-11 15:25:26 +00:00
if ( j > 0 ) { fprintf ( out , " \n " ) ; lineno + + ; }
2003-10-21 13:16:03 +00:00
fprintf ( out , " }; \n " ) ; lineno + + ;
/* Output the yy_shift_ofst[] table */
2015-09-07 18:23:37 +00:00
n = lemp - > nxstate ;
2005-11-05 15:03:59 +00:00
while ( n > 0 & & lemp - > sorted [ n - 1 ] - > iTknOfst = = NO_OFFSET ) n - - ;
2016-08-10 13:30:43 +00:00
fprintf ( out , " #define YY_SHIFT_COUNT (%d) \n " , n - 1 ) ; lineno + + ;
fprintf ( out , " #define YY_SHIFT_MIN (%d) \n " , mnTknOfst ) ; lineno + + ;
fprintf ( out , " #define YY_SHIFT_MAX (%d) \n " , mxTknOfst ) ; lineno + + ;
2017-04-14 19:46:12 +00:00
fprintf ( out , " static const %s yy_shift_ofst[] = { \n " ,
2016-08-10 13:30:43 +00:00
minimum_size_type ( mnTknOfst , lemp - > nterminal + lemp - > nactiontab , & sz ) ) ;
lineno + + ;
2015-09-07 02:23:02 +00:00
lemp - > tablesize + = n * sz ;
2003-10-21 13:16:03 +00:00
for ( i = j = 0 ; i < n ; i + + ) {
int ofst ;
stp = lemp - > sorted [ i ] ;
ofst = stp - > iTknOfst ;
2016-08-10 13:30:43 +00:00
if ( ofst = = NO_OFFSET ) ofst = lemp - > nactiontab ;
2003-10-21 16:34:41 +00:00
if ( j = = 0 ) fprintf ( out , " /* %5d */ " , i ) ;
2003-10-21 13:16:03 +00:00
fprintf ( out , " %4d, " , ofst ) ;
if ( j = = 9 | | i = = n - 1 ) {
fprintf ( out , " \n " ) ; lineno + + ;
j = 0 ;
} else {
j + + ;
2000-05-29 14:26:00 +00:00
}
2003-10-21 13:16:03 +00:00
}
fprintf ( out , " }; \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
2003-10-21 13:16:03 +00:00
/* Output the yy_reduce_ofst[] table */
2015-09-07 18:23:37 +00:00
n = lemp - > nxstate ;
2005-11-05 15:03:59 +00:00
while ( n > 0 & & lemp - > sorted [ n - 1 ] - > iNtOfst = = NO_OFFSET ) n - - ;
2009-11-03 19:18:31 +00:00
fprintf ( out , " #define YY_REDUCE_COUNT (%d) \n " , n - 1 ) ; lineno + + ;
fprintf ( out , " #define YY_REDUCE_MIN (%d) \n " , mnNtOfst ) ; lineno + + ;
fprintf ( out , " #define YY_REDUCE_MAX (%d) \n " , mxNtOfst ) ; lineno + + ;
2017-04-14 19:46:12 +00:00
fprintf ( out , " static const %s yy_reduce_ofst[] = { \n " ,
2015-09-07 02:23:02 +00:00
minimum_size_type ( mnNtOfst - 1 , mxNtOfst , & sz ) ) ; lineno + + ;
lemp - > tablesize + = n * sz ;
2003-10-21 13:16:03 +00:00
for ( i = j = 0 ; i < n ; i + + ) {
int ofst ;
stp = lemp - > sorted [ i ] ;
ofst = stp - > iNtOfst ;
if ( ofst = = NO_OFFSET ) ofst = mnNtOfst - 1 ;
2003-10-21 16:34:41 +00:00
if ( j = = 0 ) fprintf ( out , " /* %5d */ " , i ) ;
2003-10-21 13:16:03 +00:00
fprintf ( out , " %4d, " , ofst ) ;
if ( j = = 9 | | i = = n - 1 ) {
fprintf ( out , " \n " ) ; lineno + + ;
j = 0 ;
} else {
j + + ;
}
2000-05-29 14:26:00 +00:00
}
2003-10-21 13:16:03 +00:00
fprintf ( out , " }; \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
2003-10-21 13:16:03 +00:00
/* Output the default action table */
2004-10-06 15:41:16 +00:00
fprintf ( out , " static const YYACTIONTYPE yy_default[] = { \n " ) ; lineno + + ;
2015-09-07 18:23:37 +00:00
n = lemp - > nxstate ;
2015-09-07 02:23:02 +00:00
lemp - > tablesize + = n * szActionType ;
2003-10-21 13:16:03 +00:00
for ( i = j = 0 ; i < n ; i + + ) {
2000-05-29 14:26:00 +00:00
stp = lemp - > sorted [ i ] ;
2003-10-21 16:34:41 +00:00
if ( j = = 0 ) fprintf ( out , " /* %5d */ " , i ) ;
2017-12-24 23:38:10 +00:00
if ( stp - > iDfltReduce < 0 ) {
fprintf ( out , " %4d, " , lemp - > errAction ) ;
} else {
fprintf ( out , " %4d, " , stp - > iDfltReduce + lemp - > minReduce ) ;
}
2003-10-21 13:16:03 +00:00
if ( j = = 9 | | i = = n - 1 ) {
fprintf ( out , " \n " ) ; lineno + + ;
j = 0 ;
} else {
j + + ;
}
2000-05-29 14:26:00 +00:00
}
2003-10-21 13:16:03 +00:00
fprintf ( out , " }; \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
2002-06-06 18:54:39 +00:00
/* Generate the table of fallback tokens.
*/
if ( lemp - > has_fallback ) {
2009-06-12 12:50:50 +00:00
int mx = lemp - > nterminal - 1 ;
2019-08-28 11:31:11 +00:00
/* 2019-08-28: Generate fallback entries for every token to avoid
* * having to do a range check on the index */
/* while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } */
2015-09-07 02:23:02 +00:00
lemp - > tablesize + = ( mx + 1 ) * szCodeType ;
2009-06-12 12:50:50 +00:00
for ( i = 0 ; i < = mx ; i + + ) {
2002-06-06 18:54:39 +00:00
struct symbol * p = lemp - > symbols [ i ] ;
if ( p - > fallback = = 0 ) {
fprintf ( out , " 0, /* %10s => nothing */ \n " , p - > name ) ;
} else {
fprintf ( out , " %3d, /* %10s => %s */ \n " , p - > fallback - > index ,
p - > name , p - > fallback - > name ) ;
}
lineno + + ;
}
}
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Generate a table containing the symbolic name of every symbol
*/
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
2017-12-25 04:15:38 +00:00
fprintf ( out , " /* %4d */ \" %s \" , \n " , i , lemp - > symbols [ i ] - > name ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
}
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
2002-06-06 18:54:39 +00:00
/* Generate a table containing a text string that describes every
2008-07-14 12:27:51 +00:00
* * rule in the rule set of the grammar . This information is used
2002-06-06 18:54:39 +00:00
* * when tracing REDUCE actions .
*/
for ( i = 0 , rp = lemp - > rule ; rp ; rp = rp - > next , i + + ) {
2016-03-16 19:45:54 +00:00
assert ( rp - > iRule = = i ) ;
2008-01-22 01:48:05 +00:00
fprintf ( out , " /* %3d */ \" " , i ) ;
writeRuleText ( out , rp ) ;
2002-06-06 18:54:39 +00:00
fprintf ( out , " \" , \n " ) ; lineno + + ;
}
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
2000-05-29 14:26:00 +00:00
/* Generate code which executes every time a symbol is popped from
2017-04-14 19:46:12 +00:00
* * the stack while processing errors or while destroying the parser .
2002-06-06 18:54:39 +00:00
* * ( In other words , generate the % destructor actions )
*/
2000-05-29 14:26:00 +00:00
if ( lemp - > tokendest ) {
2008-07-01 17:13:57 +00:00
int once = 1 ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
struct symbol * sp = lemp - > symbols [ i ] ;
if ( sp = = 0 | | sp - > type ! = TERMINAL ) continue ;
2008-07-01 17:13:57 +00:00
if ( once ) {
fprintf ( out , " /* TERMINAL Destructor */ \n " ) ; lineno + + ;
once = 0 ;
}
2009-06-12 17:46:19 +00:00
fprintf ( out , " case %d: /* %s */ \n " , sp - > index , sp - > name ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
}
for ( i = 0 ; i < lemp - > nsymbol & & lemp - > symbols [ i ] - > type ! = TERMINAL ; i + + ) ;
if ( i < lemp - > nsymbol ) {
emit_destructor_code ( out , lemp - > symbols [ i ] , lemp , & lineno ) ;
fprintf ( out , " break; \n " ) ; lineno + + ;
}
}
2005-01-13 23:54:06 +00:00
if ( lemp - > vardest ) {
struct symbol * dflt_sp = 0 ;
2008-07-01 17:13:57 +00:00
int once = 1 ;
2005-01-13 23:54:06 +00:00
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
struct symbol * sp = lemp - > symbols [ i ] ;
if ( sp = = 0 | | sp - > type = = TERMINAL | |
sp - > index < = 0 | | sp - > destructor ! = 0 ) continue ;
2008-07-01 17:13:57 +00:00
if ( once ) {
2017-12-24 23:38:10 +00:00
fprintf ( out , " /* Default NON-TERMINAL Destructor */ \n " ) ; lineno + + ;
2008-07-01 17:13:57 +00:00
once = 0 ;
}
2009-06-12 17:46:19 +00:00
fprintf ( out , " case %d: /* %s */ \n " , sp - > index , sp - > name ) ; lineno + + ;
2005-01-13 23:54:06 +00:00
dflt_sp = sp ;
}
if ( dflt_sp ! = 0 ) {
emit_destructor_code ( out , dflt_sp , lemp , & lineno ) ;
}
2008-07-01 17:13:57 +00:00
fprintf ( out , " break; \n " ) ; lineno + + ;
2005-01-13 23:54:06 +00:00
}
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < lemp - > nsymbol ; i + + ) {
struct symbol * sp = lemp - > symbols [ i ] ;
if ( sp = = 0 | | sp - > type = = TERMINAL | | sp - > destructor = = 0 ) continue ;
2016-08-16 16:46:40 +00:00
if ( sp - > destLineno < 0 ) continue ; /* Already emitted */
2009-06-12 15:47:34 +00:00
fprintf ( out , " case %d: /* %s */ \n " , sp - > index , sp - > name ) ; lineno + + ;
2004-07-20 14:06:51 +00:00
/* Combine duplicate destructors into a single case */
for ( j = i + 1 ; j < lemp - > nsymbol ; j + + ) {
struct symbol * sp2 = lemp - > symbols [ j ] ;
if ( sp2 & & sp2 - > type ! = TERMINAL & & sp2 - > destructor
& & sp2 - > dtnum = = sp - > dtnum
& & strcmp ( sp - > destructor , sp2 - > destructor ) = = 0 ) {
2009-06-12 17:46:19 +00:00
fprintf ( out , " case %d: /* %s */ \n " ,
sp2 - > index , sp2 - > name ) ; lineno + + ;
2016-08-16 16:46:40 +00:00
sp2 - > destLineno = - 1 ; /* Avoid emitting this destructor again */
2004-07-20 14:06:51 +00:00
}
}
2000-05-29 14:26:00 +00:00
emit_destructor_code ( out , lemp - > symbols [ i ] , lemp , & lineno ) ;
fprintf ( out , " break; \n " ) ; lineno + + ;
}
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Generate code which executes whenever the parser stack overflows */
2008-04-27 22:19:44 +00:00
tplt_print ( out , lemp , lemp - > overflow , & lineno ) ;
2000-05-29 14:26:00 +00:00
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
2018-12-03 23:57:27 +00:00
/* Generate the tables of rule information. yyRuleInfoLhs[] and
* * yyRuleInfoNRhs [ ] .
2000-05-29 14:26:00 +00:00
* *
* * Note : This code depends on the fact that rules are number
2021-01-07 16:10:14 +00:00
* * sequentially beginning with 0.
2000-05-29 14:26:00 +00:00
*/
2017-12-24 23:38:10 +00:00
for ( i = 0 , rp = lemp - > rule ; rp ; rp = rp - > next , i + + ) {
2018-12-03 23:57:27 +00:00
fprintf ( out , " %4d, /* (%d) " , rp - > lhs - > index , i ) ;
rule_print ( out , rp ) ;
fprintf ( out , " */ \n " ) ; lineno + + ;
}
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
for ( i = 0 , rp = lemp - > rule ; rp ; rp = rp - > next , i + + ) {
fprintf ( out , " %3d, /* (%d) " , - rp - > nrhs , i ) ;
2017-12-24 23:38:10 +00:00
rule_print ( out , rp ) ;
fprintf ( out , " */ \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
}
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Generate code which execution during each REDUCE action */
2016-02-17 01:46:19 +00:00
i = 0 ;
2000-05-29 14:26:00 +00:00
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
2016-02-17 01:46:19 +00:00
i + = translate_code ( lemp , rp ) ;
}
if ( i ) {
fprintf ( out , " YYMINORTYPE yylhsminor; \n " ) ; lineno + + ;
2004-07-20 14:06:51 +00:00
}
2009-06-12 17:46:19 +00:00
/* First output rules other than the default: rule */
2004-07-20 14:06:51 +00:00
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
2009-06-12 17:46:19 +00:00
struct rule * rp2 ; /* Other rules with the same action */
2016-05-23 14:24:31 +00:00
if ( rp - > codeEmitted ) continue ;
if ( rp - > noCode ) {
/* No C code actions, so this will be part of the "default:" rule */
2016-04-30 17:19:30 +00:00
continue ;
}
2016-03-16 19:45:54 +00:00
fprintf ( out , " case %d: /* " , rp - > iRule ) ;
2008-01-22 01:48:05 +00:00
writeRuleText ( out , rp ) ;
fprintf ( out , " */ \n " ) ; lineno + + ;
2004-07-20 14:06:51 +00:00
for ( rp2 = rp - > next ; rp2 ; rp2 = rp2 - > next ) {
2016-04-29 11:28:35 +00:00
if ( rp2 - > code = = rp - > code & & rp2 - > codePrefix = = rp - > codePrefix
& & rp2 - > codeSuffix = = rp - > codeSuffix ) {
2016-03-16 19:45:54 +00:00
fprintf ( out , " case %d: /* " , rp2 - > iRule ) ;
2008-01-22 01:48:05 +00:00
writeRuleText ( out , rp2 ) ;
2016-03-16 19:45:54 +00:00
fprintf ( out , " */ yytestcase(yyruleno==%d); \n " , rp2 - > iRule ) ; lineno + + ;
2016-05-23 14:24:31 +00:00
rp2 - > codeEmitted = 1 ;
2004-07-20 14:06:51 +00:00
}
}
2000-05-29 14:26:00 +00:00
emit_code ( out , rp , lemp , & lineno ) ;
fprintf ( out , " break; \n " ) ; lineno + + ;
2016-05-23 14:24:31 +00:00
rp - > codeEmitted = 1 ;
2009-06-12 17:46:19 +00:00
}
/* Finally, output the default: rule. We choose as the default: all
* * empty actions . */
fprintf ( out , " default: \n " ) ; lineno + + ;
for ( rp = lemp - > rule ; rp ; rp = rp - > next ) {
2016-05-23 14:24:31 +00:00
if ( rp - > codeEmitted ) continue ;
assert ( rp - > noCode ) ;
2016-03-16 19:45:54 +00:00
fprintf ( out , " /* (%d) " , rp - > iRule ) ;
2009-06-12 17:46:19 +00:00
writeRuleText ( out , rp ) ;
2019-12-10 20:41:48 +00:00
if ( rp - > neverReduce ) {
fprintf ( out , " (NEVER REDUCES) */ assert(yyruleno!=%d); \n " ,
rp - > iRule ) ; lineno + + ;
} else if ( rp - > doesReduce ) {
2016-05-24 18:55:08 +00:00
fprintf ( out , " */ yytestcase(yyruleno==%d); \n " , rp - > iRule ) ; lineno + + ;
} else {
fprintf ( out , " (OPTIMIZED OUT) */ assert(yyruleno!=%d); \n " ,
rp - > iRule ) ; lineno + + ;
}
2000-05-29 14:26:00 +00:00
}
2009-06-12 17:46:19 +00:00
fprintf ( out , " break; \n " ) ; lineno + + ;
2000-05-29 14:26:00 +00:00
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Generate code which executes if a parse fails */
2008-04-27 22:19:44 +00:00
tplt_print ( out , lemp , lemp - > failure , & lineno ) ;
2000-05-29 14:26:00 +00:00
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Generate code which executes when a syntax error occurs */
2008-04-27 22:19:44 +00:00
tplt_print ( out , lemp , lemp - > error , & lineno ) ;
2000-05-29 14:26:00 +00:00
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Generate code which executes when the parser accepts its input */
2008-04-27 22:19:44 +00:00
tplt_print ( out , lemp , lemp - > accept , & lineno ) ;
2000-05-29 14:26:00 +00:00
tplt_xfer ( lemp - > name , in , out , & lineno ) ;
/* Append any addition code the user desires */
2008-04-27 22:19:44 +00:00
tplt_print ( out , lemp , lemp - > extracode , & lineno ) ;
2000-05-29 14:26:00 +00:00
2019-01-15 14:44:23 +00:00
acttab_free ( pActtab ) ;
2000-05-29 14:26:00 +00:00
fclose ( in ) ;
fclose ( out ) ;
2019-11-26 02:22:39 +00:00
if ( sql ) fclose ( sql ) ;
2000-05-29 14:26:00 +00:00
return ;
}
/* Generate a header file for the parser */
2010-02-14 17:14:22 +00:00
void ReportHeader ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
FILE * out , * in ;
2010-02-14 17:14:22 +00:00
const char * prefix ;
2000-05-29 14:26:00 +00:00
char line [ LINESIZE ] ;
char pattern [ LINESIZE ] ;
int i ;
if ( lemp - > tokenprefix ) prefix = lemp - > tokenprefix ;
else prefix = " " ;
2004-09-10 00:14:04 +00:00
in = file_open ( lemp , " .h " , " rb " ) ;
2000-05-29 14:26:00 +00:00
if ( in ) {
2012-06-16 15:26:31 +00:00
int nextChar ;
2000-05-29 14:26:00 +00:00
for ( i = 1 ; i < lemp - > nterminal & & fgets ( line , LINESIZE , in ) ; i + + ) {
2014-01-11 03:06:18 +00:00
lemon_sprintf ( pattern , " #define %s%-30s %3d \n " ,
prefix , lemp - > symbols [ i ] - > name , i ) ;
2000-05-29 14:26:00 +00:00
if ( strcmp ( line , pattern ) ) break ;
}
2012-06-16 15:26:31 +00:00
nextChar = fgetc ( in ) ;
2000-05-29 14:26:00 +00:00
fclose ( in ) ;
2012-06-16 15:26:31 +00:00
if ( i = = lemp - > nterminal & & nextChar = = EOF ) {
2000-05-29 14:26:00 +00:00
/* No change in the file. Don't rewrite it. */
return ;
}
}
2004-09-10 00:14:04 +00:00
out = file_open ( lemp , " .h " , " wb " ) ;
2000-05-29 14:26:00 +00:00
if ( out ) {
for ( i = 1 ; i < lemp - > nterminal ; i + + ) {
2014-01-11 03:06:18 +00:00
fprintf ( out , " #define %s%-30s %3d \n " , prefix , lemp - > symbols [ i ] - > name , i ) ;
2000-05-29 14:26:00 +00:00
}
2017-04-14 19:46:12 +00:00
fclose ( out ) ;
2000-05-29 14:26:00 +00:00
}
return ;
}
/* Reduce the size of the action tables, if possible, by making use
* * of defaults .
* *
2002-02-23 18:45:13 +00:00
* * In this version , we take the most frequent REDUCE action and make
2006-06-10 13:29:31 +00:00
* * it the default . Except , there is no default if the wildcard token
* * is a possible look - ahead .
2000-05-29 14:26:00 +00:00
*/
2010-02-14 17:14:22 +00:00
void CompressTables ( struct lemon * lemp )
2000-05-29 14:26:00 +00:00
{
struct state * stp ;
2016-05-23 16:15:02 +00:00
struct action * ap , * ap2 , * nextap ;
2002-02-23 18:45:13 +00:00
struct rule * rp , * rp2 , * rbest ;
2015-09-08 21:16:46 +00:00
int nbest , n ;
2000-05-29 14:26:00 +00:00
int i ;
2006-06-10 13:29:31 +00:00
int usesWildcard ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
stp = lemp - > sorted [ i ] ;
2002-02-23 18:45:13 +00:00
nbest = 0 ;
rbest = 0 ;
2006-06-10 13:29:31 +00:00
usesWildcard = 0 ;
2000-05-29 14:26:00 +00:00
2002-02-23 18:45:13 +00:00
for ( ap = stp - > ap ; ap ; ap = ap - > next ) {
2006-06-10 13:29:31 +00:00
if ( ap - > type = = SHIFT & & ap - > sp = = lemp - > wildcard ) {
usesWildcard = 1 ;
}
2002-02-23 18:45:13 +00:00
if ( ap - > type ! = REDUCE ) continue ;
rp = ap - > x . rp ;
2007-10-05 16:16:36 +00:00
if ( rp - > lhsStart ) continue ;
2002-02-23 18:45:13 +00:00
if ( rp = = rbest ) continue ;
n = 1 ;
for ( ap2 = ap - > next ; ap2 ; ap2 = ap2 - > next ) {
if ( ap2 - > type ! = REDUCE ) continue ;
rp2 = ap2 - > x . rp ;
if ( rp2 = = rbest ) continue ;
if ( rp2 = = rp ) n + + ;
}
if ( n > nbest ) {
nbest = n ;
rbest = rp ;
2000-05-29 14:26:00 +00:00
}
}
2017-04-14 19:46:12 +00:00
2002-02-23 18:45:13 +00:00
/* Do not make a default if the number of rules to default
2006-06-10 13:29:31 +00:00
* * is not at least 1 or if the wildcard token is a possible
* * lookahead .
*/
if ( nbest < 1 | | usesWildcard ) continue ;
2002-02-23 18:45:13 +00:00
2000-05-29 14:26:00 +00:00
2002-02-23 18:45:13 +00:00
/* Combine matching REDUCE actions into a single default */
for ( ap = stp - > ap ; ap ; ap = ap - > next ) {
if ( ap - > type = = REDUCE & & ap - > x . rp = = rbest ) break ;
}
2000-05-29 14:26:00 +00:00
assert ( ap ) ;
ap - > sp = Symbol_new ( " {default} " ) ;
for ( ap = ap - > next ; ap ; ap = ap - > next ) {
2002-02-23 18:45:13 +00:00
if ( ap - > type = = REDUCE & & ap - > x . rp = = rbest ) ap - > type = NOT_USED ;
2000-05-29 14:26:00 +00:00
}
stp - > ap = Action_sort ( stp - > ap ) ;
2015-09-07 18:23:37 +00:00
for ( ap = stp - > ap ; ap ; ap = ap - > next ) {
if ( ap - > type = = SHIFT ) break ;
if ( ap - > type = = REDUCE & & ap - > x . rp ! = rbest ) break ;
}
if ( ap = = 0 ) {
stp - > autoReduce = 1 ;
stp - > pDfltReduce = rbest ;
}
}
/* Make a second pass over all states and actions. Convert
* * every action that is a SHIFT to an autoReduce state into
* * a SHIFTREDUCE action .
*/
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
stp = lemp - > sorted [ i ] ;
for ( ap = stp - > ap ; ap ; ap = ap - > next ) {
struct state * pNextState ;
if ( ap - > type ! = SHIFT ) continue ;
pNextState = ap - > x . stp ;
if ( pNextState - > autoReduce & & pNextState - > pDfltReduce ! = 0 ) {
ap - > type = SHIFTREDUCE ;
ap - > x . rp = pNextState - > pDfltReduce ;
}
}
2000-05-29 14:26:00 +00:00
}
2016-05-23 16:15:02 +00:00
/* If a SHIFTREDUCE action specifies a rule that has a single RHS term
* * ( meaning that the SHIFTREDUCE will land back in the state where it
* * started ) and if there is no C - code associated with the reduce action ,
* * then we can go ahead and convert the action to be the same as the
* * action for the RHS of the rule .
*/
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
stp = lemp - > sorted [ i ] ;
for ( ap = stp - > ap ; ap ; ap = nextap ) {
nextap = ap - > next ;
if ( ap - > type ! = SHIFTREDUCE ) continue ;
rp = ap - > x . rp ;
if ( rp - > noCode = = 0 ) continue ;
if ( rp - > nrhs ! = 1 ) continue ;
# if 1
/* Only apply this optimization to non-terminals. It would be OK to
* * apply it to terminal symbols too , but that makes the parser tables
* * larger . */
if ( ap - > sp - > index < lemp - > nterminal ) continue ;
# endif
/* If we reach this point, it means the optimization can be applied */
nextap = ap ;
for ( ap2 = stp - > ap ; ap2 & & ( ap2 = = ap | | ap2 - > sp ! = rp - > lhs ) ; ap2 = ap2 - > next ) { }
assert ( ap2 ! = 0 ) ;
ap - > spOpt = ap2 - > sp ;
ap - > type = ap2 - > type ;
ap - > x = ap2 - > x ;
}
}
2000-05-29 14:26:00 +00:00
}
2002-02-23 18:45:13 +00:00
2005-11-05 15:03:59 +00:00
/*
* * Compare two states for sorting purposes . The smaller state is the
* * one with the most non - terminal actions . If they have the same number
* * of non - terminal actions , then the smaller is the one with the most
* * token actions .
*/
static int stateResortCompare ( const void * a , const void * b ) {
const struct state * pA = * ( const struct state * * ) a ;
const struct state * pB = * ( const struct state * * ) b ;
int n ;
n = pB - > nNtAct - pA - > nNtAct ;
if ( n = = 0 ) {
n = pB - > nTknAct - pA - > nTknAct ;
2009-11-03 13:02:25 +00:00
if ( n = = 0 ) {
n = pB - > statenum - pA - > statenum ;
}
2005-11-05 15:03:59 +00:00
}
2009-11-03 13:02:25 +00:00
assert ( n ! = 0 ) ;
2005-11-05 15:03:59 +00:00
return n ;
}
/*
* * Renumber and resort states so that states with fewer choices
* * occur at the end . Except , keep state 0 as the first state .
*/
2010-02-14 17:14:22 +00:00
void ResortStates ( struct lemon * lemp )
2005-11-05 15:03:59 +00:00
{
int i ;
struct state * stp ;
struct action * ap ;
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
stp = lemp - > sorted [ i ] ;
stp - > nTknAct = stp - > nNtAct = 0 ;
2017-12-24 23:38:10 +00:00
stp - > iDfltReduce = - 1 ; /* Init dflt action to "syntax error" */
2005-11-05 15:03:59 +00:00
stp - > iTknOfst = NO_OFFSET ;
stp - > iNtOfst = NO_OFFSET ;
for ( ap = stp - > ap ; ap ; ap = ap - > next ) {
2015-09-07 18:23:37 +00:00
int iAction = compute_action ( lemp , ap ) ;
if ( iAction > = 0 ) {
2005-11-05 15:03:59 +00:00
if ( ap - > sp - > index < lemp - > nterminal ) {
stp - > nTknAct + + ;
} else if ( ap - > sp - > index < lemp - > nsymbol ) {
stp - > nNtAct + + ;
} else {
2015-09-07 18:23:37 +00:00
assert ( stp - > autoReduce = = 0 | | stp - > pDfltReduce = = ap - > x . rp ) ;
2017-12-24 23:38:10 +00:00
stp - > iDfltReduce = iAction ;
2005-11-05 15:03:59 +00:00
}
}
}
}
qsort ( & lemp - > sorted [ 1 ] , lemp - > nstate - 1 , sizeof ( lemp - > sorted [ 0 ] ) ,
stateResortCompare ) ;
for ( i = 0 ; i < lemp - > nstate ; i + + ) {
lemp - > sorted [ i ] - > statenum = i ;
}
2015-09-07 18:23:37 +00:00
lemp - > nxstate = lemp - > nstate ;
while ( lemp - > nxstate > 1 & & lemp - > sorted [ lemp - > nxstate - 1 ] - > autoReduce ) {
lemp - > nxstate - - ;
}
2005-11-05 15:03:59 +00:00
}
2000-05-29 14:26:00 +00:00
/***************** From the file "set.c" ************************************/
/*
* * Set manipulation routines for the LEMON parser generator .
*/
static int size = 0 ;
/* Set the set size */
2010-02-14 17:14:22 +00:00
void SetSize ( int n )
2000-05-29 14:26:00 +00:00
{
size = n + 1 ;
}
/* Allocate a new set */
2017-04-14 19:44:15 +00:00
char * SetNew ( void ) {
2000-05-29 14:26:00 +00:00
char * s ;
2007-12-21 00:02:11 +00:00
s = ( char * ) calloc ( size , 1 ) ;
2000-05-29 14:26:00 +00:00
if ( s = = 0 ) {
memory_error ( ) ;
}
return s ;
}
/* Deallocate a set */
2010-02-14 17:14:22 +00:00
void SetFree ( char * s )
2000-05-29 14:26:00 +00:00
{
free ( s ) ;
}
/* Add a new element to the set. Return TRUE if the element was added
* * and FALSE if it was already there . */
2010-02-14 17:14:22 +00:00
int SetAdd ( char * s , int e )
2000-05-29 14:26:00 +00:00
{
int rv ;
2007-12-21 00:02:11 +00:00
assert ( e > = 0 & & e < size ) ;
2000-05-29 14:26:00 +00:00
rv = s [ e ] ;
s [ e ] = 1 ;
return ! rv ;
}
/* Add every element of s2 to s1. Return TRUE if s1 changes. */
2010-02-14 17:14:22 +00:00
int SetUnion ( char * s1 , char * s2 )
2000-05-29 14:26:00 +00:00
{
int i , progress ;
progress = 0 ;
for ( i = 0 ; i < size ; i + + ) {
if ( s2 [ i ] = = 0 ) continue ;
if ( s1 [ i ] = = 0 ) {
progress = 1 ;
s1 [ i ] = 1 ;
}
}
return progress ;
}
/********************** From the file "table.c" ****************************/
/*
* * All code in this file has been automatically generated
* * from a specification in the file
* * " table.q "
* * by the associative array code building program " aagen " .
* * Do not edit this file ! Instead , edit the specification
* * file , then rerun aagen .
*/
/*
* * Code for processing tables in the LEMON parser generator .
*/
2013-10-02 20:46:30 +00:00
PRIVATE unsigned strhash ( const char * x )
2000-05-29 14:26:00 +00:00
{
2013-10-02 20:46:30 +00:00
unsigned h = 0 ;
while ( * x ) h = h * 13 + * ( x + + ) ;
2000-05-29 14:26:00 +00:00
return h ;
}
/* Works like strdup, sort of. Save a string in malloced memory, but
* * keep strings in a table so that the same string is not in more
* * than one place .
*/
2010-02-14 17:14:22 +00:00
const char * Strsafe ( const char * y )
2000-05-29 14:26:00 +00:00
{
2010-02-14 17:14:22 +00:00
const char * z ;
char * cpy ;
2000-05-29 14:26:00 +00:00
2006-07-17 00:19:39 +00:00
if ( y = = 0 ) return 0 ;
2000-05-29 14:26:00 +00:00
z = Strsafe_find ( y ) ;
2010-02-14 17:14:22 +00:00
if ( z = = 0 & & ( cpy = ( char * ) malloc ( lemonStrlen ( y ) + 1 ) ) ! = 0 ) {
2014-01-10 23:21:00 +00:00
lemon_strcpy ( cpy , y ) ;
2010-02-14 17:14:22 +00:00
z = cpy ;
2000-05-29 14:26:00 +00:00
Strsafe_insert ( z ) ;
}
MemoryCheck ( z ) ;
return z ;
}
/* There is one instance of the following structure for each
* * associative array of type " x1 " .
*/
struct s_x1 {
int size ; /* The number of available slots. */
/* Must be a power of 2 greater than or */
/* equal to 1 */
int count ; /* Number of currently slots filled */
struct s_x1node * tbl ; /* The data stored here */
struct s_x1node * * ht ; /* Hash table for lookups */
} ;
/* There is one instance of this structure for every data element
* * in an associative array of type " x1 " .
*/
typedef struct s_x1node {
2010-02-14 17:14:22 +00:00
const char * data ; /* The data */
2000-05-29 14:26:00 +00:00
struct s_x1node * next ; /* Next entry with the same hash */
struct s_x1node * * from ; /* Previous link */
} x1node ;
/* There is only one instance of the array, which is the following */
static struct s_x1 * x1a ;
/* Allocate a new associative array */
2017-04-14 19:44:15 +00:00
void Strsafe_init ( void ) {
2000-05-29 14:26:00 +00:00
if ( x1a ) return ;
x1a = ( struct s_x1 * ) malloc ( sizeof ( struct s_x1 ) ) ;
if ( x1a ) {
x1a - > size = 1024 ;
x1a - > count = 0 ;
2014-01-11 12:52:25 +00:00
x1a - > tbl = ( x1node * ) calloc ( 1024 , sizeof ( x1node ) + sizeof ( x1node * ) ) ;
2000-05-29 14:26:00 +00:00
if ( x1a - > tbl = = 0 ) {
free ( x1a ) ;
x1a = 0 ;
} else {
int i ;
x1a - > ht = ( x1node * * ) & ( x1a - > tbl [ 1024 ] ) ;
for ( i = 0 ; i < 1024 ; i + + ) x1a - > ht [ i ] = 0 ;
}
}
}
/* Insert a new record into the array. Return TRUE if successful.
* * Prior data with the same key is NOT overwritten */
2010-02-14 17:14:22 +00:00
int Strsafe_insert ( const char * data )
2000-05-29 14:26:00 +00:00
{
x1node * np ;
2013-10-02 20:46:30 +00:00
unsigned h ;
unsigned ph ;
2000-05-29 14:26:00 +00:00
if ( x1a = = 0 ) return 0 ;
ph = strhash ( data ) ;
h = ph & ( x1a - > size - 1 ) ;
np = x1a - > ht [ h ] ;
while ( np ) {
if ( strcmp ( np - > data , data ) = = 0 ) {
/* An existing entry with the same key is found. */
/* Fail because overwrite is not allows. */
return 0 ;
}
np = np - > next ;
}
if ( x1a - > count > = x1a - > size ) {
/* Need to make the hash table bigger */
2015-04-19 21:43:16 +00:00
int i , arrSize ;
2000-05-29 14:26:00 +00:00
struct s_x1 array ;
2015-04-19 21:43:16 +00:00
array . size = arrSize = x1a - > size * 2 ;
2000-05-29 14:26:00 +00:00
array . count = x1a - > count ;
2015-04-19 21:43:16 +00:00
array . tbl = ( x1node * ) calloc ( arrSize , sizeof ( x1node ) + sizeof ( x1node * ) ) ;
2000-05-29 14:26:00 +00:00
if ( array . tbl = = 0 ) return 0 ; /* Fail due to malloc failure */
2015-04-19 21:43:16 +00:00
array . ht = ( x1node * * ) & ( array . tbl [ arrSize ] ) ;
for ( i = 0 ; i < arrSize ; i + + ) array . ht [ i ] = 0 ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < x1a - > count ; i + + ) {
x1node * oldnp , * newnp ;
oldnp = & ( x1a - > tbl [ i ] ) ;
2015-04-19 21:43:16 +00:00
h = strhash ( oldnp - > data ) & ( arrSize - 1 ) ;
2000-05-29 14:26:00 +00:00
newnp = & ( array . tbl [ i ] ) ;
if ( array . ht [ h ] ) array . ht [ h ] - > from = & ( newnp - > next ) ;
newnp - > next = array . ht [ h ] ;
newnp - > data = oldnp - > data ;
newnp - > from = & ( array . ht [ h ] ) ;
array . ht [ h ] = newnp ;
}
2021-10-04 16:14:51 +00:00
/* free(x1a->tbl); // This program was originally for 16-bit machines.
* * Don ' t worry about freeing memory on modern platforms . */
2000-05-29 14:26:00 +00:00
* x1a = array ;
}
/* Insert the new data */
h = ph & ( x1a - > size - 1 ) ;
np = & ( x1a - > tbl [ x1a - > count + + ] ) ;
np - > data = data ;
if ( x1a - > ht [ h ] ) x1a - > ht [ h ] - > from = & ( np - > next ) ;
np - > next = x1a - > ht [ h ] ;
x1a - > ht [ h ] = np ;
np - > from = & ( x1a - > ht [ h ] ) ;
return 1 ;
}
/* Return a pointer to data assigned to the given key. Return NULL
* * if no such key . */
2010-02-14 17:14:22 +00:00
const char * Strsafe_find ( const char * key )
2000-05-29 14:26:00 +00:00
{
2013-10-02 20:46:30 +00:00
unsigned h ;
2000-05-29 14:26:00 +00:00
x1node * np ;
if ( x1a = = 0 ) return 0 ;
h = strhash ( key ) & ( x1a - > size - 1 ) ;
np = x1a - > ht [ h ] ;
while ( np ) {
if ( strcmp ( np - > data , key ) = = 0 ) break ;
np = np - > next ;
}
return np ? np - > data : 0 ;
}
/* Return a pointer to the (terminal or nonterminal) symbol "x".
* * Create a new symbol if this is the first time " x " has been seen .
*/
2010-02-14 17:14:22 +00:00
struct symbol * Symbol_new ( const char * x )
2000-05-29 14:26:00 +00:00
{
struct symbol * sp ;
sp = Symbol_find ( x ) ;
if ( sp = = 0 ) {
2007-12-21 00:02:11 +00:00
sp = ( struct symbol * ) calloc ( 1 , sizeof ( struct symbol ) ) ;
2000-05-29 14:26:00 +00:00
MemoryCheck ( sp ) ;
sp - > name = Strsafe ( x ) ;
2015-10-29 13:48:15 +00:00
sp - > type = ISUPPER ( * x ) ? TERMINAL : NONTERMINAL ;
2000-05-29 14:26:00 +00:00
sp - > rule = 0 ;
2002-06-06 18:54:39 +00:00
sp - > fallback = 0 ;
2000-05-29 14:26:00 +00:00
sp - > prec = - 1 ;
sp - > assoc = UNK ;
sp - > firstset = 0 ;
2007-08-23 02:50:56 +00:00
sp - > lambda = LEMON_FALSE ;
2000-05-29 14:26:00 +00:00
sp - > destructor = 0 ;
2008-07-01 17:13:57 +00:00
sp - > destLineno = 0 ;
2000-05-29 14:26:00 +00:00
sp - > datatype = 0 ;
2008-01-22 01:48:05 +00:00
sp - > useCnt = 0 ;
2000-05-29 14:26:00 +00:00
Symbol_insert ( sp , sp - > name ) ;
}
2008-01-22 01:48:05 +00:00
sp - > useCnt + + ;
2000-05-29 14:26:00 +00:00
return sp ;
}
2014-01-11 03:06:18 +00:00
/* Compare two symbols for sorting purposes. Return negative,
* * zero , or positive if a is less then , equal to , or greater
* * than b .
2004-02-22 00:08:04 +00:00
* *
* * Symbols that begin with upper case letters ( terminals or tokens )
* * must sort before symbols that begin with lower case letters
2014-01-11 03:06:18 +00:00
* * ( non - terminals ) . And MULTITERMINAL symbols ( created using the
* * % token_class directive ) must sort at the very end . Other than
* * that , the order does not matter .
2004-02-22 00:08:04 +00:00
* *
* * We find experimentally that leaving the symbols in their original
* * order ( the order they appeared in the grammar file ) gives the
* * smallest parser tables in SQLite .
*/
2010-02-14 17:14:22 +00:00
int Symbolcmpp ( const void * _a , const void * _b )
{
2014-01-11 03:06:18 +00:00
const struct symbol * a = * ( const struct symbol * * ) _a ;
const struct symbol * b = * ( const struct symbol * * ) _b ;
int i1 = a - > type = = MULTITERMINAL ? 3 : a - > name [ 0 ] > ' Z ' ? 2 : 1 ;
int i2 = b - > type = = MULTITERMINAL ? 3 : b - > name [ 0 ] > ' Z ' ? 2 : 1 ;
return i1 = = i2 ? a - > index - b - > index : i1 - i2 ;
2000-05-29 14:26:00 +00:00
}
/* There is one instance of the following structure for each
* * associative array of type " x2 " .
*/
struct s_x2 {
int size ; /* The number of available slots. */
/* Must be a power of 2 greater than or */
/* equal to 1 */
int count ; /* Number of currently slots filled */
struct s_x2node * tbl ; /* The data stored here */
struct s_x2node * * ht ; /* Hash table for lookups */
} ;
/* There is one instance of this structure for every data element
* * in an associative array of type " x2 " .
*/
typedef struct s_x2node {
2010-02-14 17:14:22 +00:00
struct symbol * data ; /* The data */
const char * key ; /* The key */
2000-05-29 14:26:00 +00:00
struct s_x2node * next ; /* Next entry with the same hash */
struct s_x2node * * from ; /* Previous link */
} x2node ;
/* There is only one instance of the array, which is the following */
static struct s_x2 * x2a ;
/* Allocate a new associative array */
2017-04-14 19:44:15 +00:00
void Symbol_init ( void ) {
2000-05-29 14:26:00 +00:00
if ( x2a ) return ;
x2a = ( struct s_x2 * ) malloc ( sizeof ( struct s_x2 ) ) ;
if ( x2a ) {
x2a - > size = 128 ;
x2a - > count = 0 ;
2014-01-11 12:52:25 +00:00
x2a - > tbl = ( x2node * ) calloc ( 128 , sizeof ( x2node ) + sizeof ( x2node * ) ) ;
2000-05-29 14:26:00 +00:00
if ( x2a - > tbl = = 0 ) {
free ( x2a ) ;
x2a = 0 ;
} else {
int i ;
x2a - > ht = ( x2node * * ) & ( x2a - > tbl [ 128 ] ) ;
for ( i = 0 ; i < 128 ; i + + ) x2a - > ht [ i ] = 0 ;
}
}
}
/* Insert a new record into the array. Return TRUE if successful.
* * Prior data with the same key is NOT overwritten */
2010-02-14 17:14:22 +00:00
int Symbol_insert ( struct symbol * data , const char * key )
2000-05-29 14:26:00 +00:00
{
x2node * np ;
2013-10-02 20:46:30 +00:00
unsigned h ;
unsigned ph ;
2000-05-29 14:26:00 +00:00
if ( x2a = = 0 ) return 0 ;
ph = strhash ( key ) ;
h = ph & ( x2a - > size - 1 ) ;
np = x2a - > ht [ h ] ;
while ( np ) {
if ( strcmp ( np - > key , key ) = = 0 ) {
/* An existing entry with the same key is found. */
/* Fail because overwrite is not allows. */
return 0 ;
}
np = np - > next ;
}
if ( x2a - > count > = x2a - > size ) {
/* Need to make the hash table bigger */
2015-04-19 21:43:16 +00:00
int i , arrSize ;
2000-05-29 14:26:00 +00:00
struct s_x2 array ;
2015-04-19 21:43:16 +00:00
array . size = arrSize = x2a - > size * 2 ;
2000-05-29 14:26:00 +00:00
array . count = x2a - > count ;
2015-04-19 21:43:16 +00:00
array . tbl = ( x2node * ) calloc ( arrSize , sizeof ( x2node ) + sizeof ( x2node * ) ) ;
2000-05-29 14:26:00 +00:00
if ( array . tbl = = 0 ) return 0 ; /* Fail due to malloc failure */
2015-04-19 21:43:16 +00:00
array . ht = ( x2node * * ) & ( array . tbl [ arrSize ] ) ;
for ( i = 0 ; i < arrSize ; i + + ) array . ht [ i ] = 0 ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < x2a - > count ; i + + ) {
x2node * oldnp , * newnp ;
oldnp = & ( x2a - > tbl [ i ] ) ;
2015-04-19 21:43:16 +00:00
h = strhash ( oldnp - > key ) & ( arrSize - 1 ) ;
2000-05-29 14:26:00 +00:00
newnp = & ( array . tbl [ i ] ) ;
if ( array . ht [ h ] ) array . ht [ h ] - > from = & ( newnp - > next ) ;
newnp - > next = array . ht [ h ] ;
newnp - > key = oldnp - > key ;
newnp - > data = oldnp - > data ;
newnp - > from = & ( array . ht [ h ] ) ;
array . ht [ h ] = newnp ;
}
2021-10-04 16:14:51 +00:00
/* free(x2a->tbl); // This program was originally written for 16-bit
* * machines . Don ' t worry about freeing this trivial amount of memory
* * on modern platforms . Just leak it . */
2000-05-29 14:26:00 +00:00
* x2a = array ;
}
/* Insert the new data */
h = ph & ( x2a - > size - 1 ) ;
np = & ( x2a - > tbl [ x2a - > count + + ] ) ;
np - > key = key ;
np - > data = data ;
if ( x2a - > ht [ h ] ) x2a - > ht [ h ] - > from = & ( np - > next ) ;
np - > next = x2a - > ht [ h ] ;
x2a - > ht [ h ] = np ;
np - > from = & ( x2a - > ht [ h ] ) ;
return 1 ;
}
/* Return a pointer to data assigned to the given key. Return NULL
* * if no such key . */
2010-02-14 17:14:22 +00:00
struct symbol * Symbol_find ( const char * key )
2000-05-29 14:26:00 +00:00
{
2013-10-02 20:46:30 +00:00
unsigned h ;
2000-05-29 14:26:00 +00:00
x2node * np ;
if ( x2a = = 0 ) return 0 ;
h = strhash ( key ) & ( x2a - > size - 1 ) ;
np = x2a - > ht [ h ] ;
while ( np ) {
if ( strcmp ( np - > key , key ) = = 0 ) break ;
np = np - > next ;
}
return np ? np - > data : 0 ;
}
/* Return the n-th data. Return NULL if n is out of range. */
2010-02-14 17:14:22 +00:00
struct symbol * Symbol_Nth ( int n )
2000-05-29 14:26:00 +00:00
{
struct symbol * data ;
if ( x2a & & n > 0 & & n < = x2a - > count ) {
data = x2a - > tbl [ n - 1 ] . data ;
} else {
data = 0 ;
}
return data ;
}
/* Return the size of the array */
int Symbol_count ( )
{
return x2a ? x2a - > count : 0 ;
}
/* Return an array of pointers to all data in the table.
* * The array is obtained from malloc . Return NULL if memory allocation
* * problems , or if the array is empty . */
struct symbol * * Symbol_arrayof ( )
{
struct symbol * * array ;
2015-04-19 21:43:16 +00:00
int i , arrSize ;
2000-05-29 14:26:00 +00:00
if ( x2a = = 0 ) return 0 ;
2015-04-19 21:43:16 +00:00
arrSize = x2a - > count ;
array = ( struct symbol * * ) calloc ( arrSize , sizeof ( struct symbol * ) ) ;
2000-05-29 14:26:00 +00:00
if ( array ) {
2015-04-19 21:43:16 +00:00
for ( i = 0 ; i < arrSize ; i + + ) array [ i ] = x2a - > tbl [ i ] . data ;
2000-05-29 14:26:00 +00:00
}
return array ;
}
/* Compare two configurations */
2010-02-14 17:14:22 +00:00
int Configcmp ( const char * _a , const char * _b )
2000-05-29 14:26:00 +00:00
{
2010-02-14 17:14:22 +00:00
const struct config * a = ( struct config * ) _a ;
const struct config * b = ( struct config * ) _b ;
2000-05-29 14:26:00 +00:00
int x ;
x = a - > rp - > index - b - > rp - > index ;
if ( x = = 0 ) x = a - > dot - b - > dot ;
return x ;
}
/* Compare two states */
2010-02-14 17:14:22 +00:00
PRIVATE int statecmp ( struct config * a , struct config * b )
2000-05-29 14:26:00 +00:00
{
int rc ;
for ( rc = 0 ; rc = = 0 & & a & & b ; a = a - > bp , b = b - > bp ) {
rc = a - > rp - > index - b - > rp - > index ;
if ( rc = = 0 ) rc = a - > dot - b - > dot ;
}
if ( rc = = 0 ) {
if ( a ) rc = 1 ;
if ( b ) rc = - 1 ;
}
return rc ;
}
/* Hash a state */
2013-10-02 20:46:30 +00:00
PRIVATE unsigned statehash ( struct config * a )
2000-05-29 14:26:00 +00:00
{
2013-10-02 20:46:30 +00:00
unsigned h = 0 ;
2000-05-29 14:26:00 +00:00
while ( a ) {
h = h * 571 + a - > rp - > index * 37 + a - > dot ;
a = a - > bp ;
}
return h ;
}
/* Allocate a new state structure */
struct state * State_new ( )
{
2010-02-14 17:14:22 +00:00
struct state * newstate ;
newstate = ( struct state * ) calloc ( 1 , sizeof ( struct state ) ) ;
MemoryCheck ( newstate ) ;
return newstate ;
2000-05-29 14:26:00 +00:00
}
/* There is one instance of the following structure for each
* * associative array of type " x3 " .
*/
struct s_x3 {
int size ; /* The number of available slots. */
/* Must be a power of 2 greater than or */
/* equal to 1 */
int count ; /* Number of currently slots filled */
struct s_x3node * tbl ; /* The data stored here */
struct s_x3node * * ht ; /* Hash table for lookups */
} ;
/* There is one instance of this structure for every data element
* * in an associative array of type " x3 " .
*/
typedef struct s_x3node {
struct state * data ; /* The data */
struct config * key ; /* The key */
struct s_x3node * next ; /* Next entry with the same hash */
struct s_x3node * * from ; /* Previous link */
} x3node ;
/* There is only one instance of the array, which is the following */
static struct s_x3 * x3a ;
/* Allocate a new associative array */
2017-04-14 19:44:15 +00:00
void State_init ( void ) {
2000-05-29 14:26:00 +00:00
if ( x3a ) return ;
x3a = ( struct s_x3 * ) malloc ( sizeof ( struct s_x3 ) ) ;
if ( x3a ) {
x3a - > size = 128 ;
x3a - > count = 0 ;
2014-01-11 12:52:25 +00:00
x3a - > tbl = ( x3node * ) calloc ( 128 , sizeof ( x3node ) + sizeof ( x3node * ) ) ;
2000-05-29 14:26:00 +00:00
if ( x3a - > tbl = = 0 ) {
free ( x3a ) ;
x3a = 0 ;
} else {
int i ;
x3a - > ht = ( x3node * * ) & ( x3a - > tbl [ 128 ] ) ;
for ( i = 0 ; i < 128 ; i + + ) x3a - > ht [ i ] = 0 ;
}
}
}
/* Insert a new record into the array. Return TRUE if successful.
* * Prior data with the same key is NOT overwritten */
2010-02-14 17:14:22 +00:00
int State_insert ( struct state * data , struct config * key )
2000-05-29 14:26:00 +00:00
{
x3node * np ;
2013-10-02 20:46:30 +00:00
unsigned h ;
unsigned ph ;
2000-05-29 14:26:00 +00:00
if ( x3a = = 0 ) return 0 ;
ph = statehash ( key ) ;
h = ph & ( x3a - > size - 1 ) ;
np = x3a - > ht [ h ] ;
while ( np ) {
if ( statecmp ( np - > key , key ) = = 0 ) {
/* An existing entry with the same key is found. */
/* Fail because overwrite is not allows. */
return 0 ;
}
np = np - > next ;
}
if ( x3a - > count > = x3a - > size ) {
/* Need to make the hash table bigger */
2015-04-19 21:43:16 +00:00
int i , arrSize ;
2000-05-29 14:26:00 +00:00
struct s_x3 array ;
2015-04-19 21:43:16 +00:00
array . size = arrSize = x3a - > size * 2 ;
2000-05-29 14:26:00 +00:00
array . count = x3a - > count ;
2015-04-19 21:43:16 +00:00
array . tbl = ( x3node * ) calloc ( arrSize , sizeof ( x3node ) + sizeof ( x3node * ) ) ;
2000-05-29 14:26:00 +00:00
if ( array . tbl = = 0 ) return 0 ; /* Fail due to malloc failure */
2015-04-19 21:43:16 +00:00
array . ht = ( x3node * * ) & ( array . tbl [ arrSize ] ) ;
for ( i = 0 ; i < arrSize ; i + + ) array . ht [ i ] = 0 ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < x3a - > count ; i + + ) {
x3node * oldnp , * newnp ;
oldnp = & ( x3a - > tbl [ i ] ) ;
2015-04-19 21:43:16 +00:00
h = statehash ( oldnp - > key ) & ( arrSize - 1 ) ;
2000-05-29 14:26:00 +00:00
newnp = & ( array . tbl [ i ] ) ;
if ( array . ht [ h ] ) array . ht [ h ] - > from = & ( newnp - > next ) ;
newnp - > next = array . ht [ h ] ;
newnp - > key = oldnp - > key ;
newnp - > data = oldnp - > data ;
newnp - > from = & ( array . ht [ h ] ) ;
array . ht [ h ] = newnp ;
}
free ( x3a - > tbl ) ;
* x3a = array ;
}
/* Insert the new data */
h = ph & ( x3a - > size - 1 ) ;
np = & ( x3a - > tbl [ x3a - > count + + ] ) ;
np - > key = key ;
np - > data = data ;
if ( x3a - > ht [ h ] ) x3a - > ht [ h ] - > from = & ( np - > next ) ;
np - > next = x3a - > ht [ h ] ;
x3a - > ht [ h ] = np ;
np - > from = & ( x3a - > ht [ h ] ) ;
return 1 ;
}
/* Return a pointer to data assigned to the given key. Return NULL
* * if no such key . */
2010-02-14 17:14:22 +00:00
struct state * State_find ( struct config * key )
2000-05-29 14:26:00 +00:00
{
2013-10-02 20:46:30 +00:00
unsigned h ;
2000-05-29 14:26:00 +00:00
x3node * np ;
if ( x3a = = 0 ) return 0 ;
h = statehash ( key ) & ( x3a - > size - 1 ) ;
np = x3a - > ht [ h ] ;
while ( np ) {
if ( statecmp ( np - > key , key ) = = 0 ) break ;
np = np - > next ;
}
return np ? np - > data : 0 ;
}
/* Return an array of pointers to all data in the table.
* * The array is obtained from malloc . Return NULL if memory allocation
* * problems , or if the array is empty . */
2017-04-14 19:44:15 +00:00
struct state * * State_arrayof ( void )
2000-05-29 14:26:00 +00:00
{
struct state * * array ;
2015-04-19 21:43:16 +00:00
int i , arrSize ;
2000-05-29 14:26:00 +00:00
if ( x3a = = 0 ) return 0 ;
2015-04-19 21:43:16 +00:00
arrSize = x3a - > count ;
array = ( struct state * * ) calloc ( arrSize , sizeof ( struct state * ) ) ;
2000-05-29 14:26:00 +00:00
if ( array ) {
2015-04-19 21:43:16 +00:00
for ( i = 0 ; i < arrSize ; i + + ) array [ i ] = x3a - > tbl [ i ] . data ;
2000-05-29 14:26:00 +00:00
}
return array ;
}
/* Hash a configuration */
2013-10-02 20:46:30 +00:00
PRIVATE unsigned confighash ( struct config * a )
2000-05-29 14:26:00 +00:00
{
2013-10-02 20:46:30 +00:00
unsigned h = 0 ;
2000-05-29 14:26:00 +00:00
h = h * 571 + a - > rp - > index * 37 + a - > dot ;
return h ;
}
/* There is one instance of the following structure for each
* * associative array of type " x4 " .
*/
struct s_x4 {
int size ; /* The number of available slots. */
/* Must be a power of 2 greater than or */
/* equal to 1 */
int count ; /* Number of currently slots filled */
struct s_x4node * tbl ; /* The data stored here */
struct s_x4node * * ht ; /* Hash table for lookups */
} ;
/* There is one instance of this structure for every data element
* * in an associative array of type " x4 " .
*/
typedef struct s_x4node {
struct config * data ; /* The data */
struct s_x4node * next ; /* Next entry with the same hash */
struct s_x4node * * from ; /* Previous link */
} x4node ;
/* There is only one instance of the array, which is the following */
static struct s_x4 * x4a ;
/* Allocate a new associative array */
2017-04-14 19:44:15 +00:00
void Configtable_init ( void ) {
2000-05-29 14:26:00 +00:00
if ( x4a ) return ;
x4a = ( struct s_x4 * ) malloc ( sizeof ( struct s_x4 ) ) ;
if ( x4a ) {
x4a - > size = 64 ;
x4a - > count = 0 ;
2014-01-11 12:52:25 +00:00
x4a - > tbl = ( x4node * ) calloc ( 64 , sizeof ( x4node ) + sizeof ( x4node * ) ) ;
2000-05-29 14:26:00 +00:00
if ( x4a - > tbl = = 0 ) {
free ( x4a ) ;
x4a = 0 ;
} else {
int i ;
x4a - > ht = ( x4node * * ) & ( x4a - > tbl [ 64 ] ) ;
for ( i = 0 ; i < 64 ; i + + ) x4a - > ht [ i ] = 0 ;
}
}
}
/* Insert a new record into the array. Return TRUE if successful.
* * Prior data with the same key is NOT overwritten */
2010-02-14 17:14:22 +00:00
int Configtable_insert ( struct config * data )
2000-05-29 14:26:00 +00:00
{
x4node * np ;
2013-10-02 20:46:30 +00:00
unsigned h ;
unsigned ph ;
2000-05-29 14:26:00 +00:00
if ( x4a = = 0 ) return 0 ;
ph = confighash ( data ) ;
h = ph & ( x4a - > size - 1 ) ;
np = x4a - > ht [ h ] ;
while ( np ) {
2010-02-14 17:14:22 +00:00
if ( Configcmp ( ( const char * ) np - > data , ( const char * ) data ) = = 0 ) {
2000-05-29 14:26:00 +00:00
/* An existing entry with the same key is found. */
/* Fail because overwrite is not allows. */
return 0 ;
}
np = np - > next ;
}
if ( x4a - > count > = x4a - > size ) {
/* Need to make the hash table bigger */
2015-04-19 21:43:16 +00:00
int i , arrSize ;
2000-05-29 14:26:00 +00:00
struct s_x4 array ;
2015-04-19 21:43:16 +00:00
array . size = arrSize = x4a - > size * 2 ;
2000-05-29 14:26:00 +00:00
array . count = x4a - > count ;
2015-04-19 21:43:16 +00:00
array . tbl = ( x4node * ) calloc ( arrSize , sizeof ( x4node ) + sizeof ( x4node * ) ) ;
2000-05-29 14:26:00 +00:00
if ( array . tbl = = 0 ) return 0 ; /* Fail due to malloc failure */
2015-04-19 21:43:16 +00:00
array . ht = ( x4node * * ) & ( array . tbl [ arrSize ] ) ;
for ( i = 0 ; i < arrSize ; i + + ) array . ht [ i ] = 0 ;
2000-05-29 14:26:00 +00:00
for ( i = 0 ; i < x4a - > count ; i + + ) {
x4node * oldnp , * newnp ;
oldnp = & ( x4a - > tbl [ i ] ) ;
2015-04-19 21:43:16 +00:00
h = confighash ( oldnp - > data ) & ( arrSize - 1 ) ;
2000-05-29 14:26:00 +00:00
newnp = & ( array . tbl [ i ] ) ;
if ( array . ht [ h ] ) array . ht [ h ] - > from = & ( newnp - > next ) ;
newnp - > next = array . ht [ h ] ;
newnp - > data = oldnp - > data ;
newnp - > from = & ( array . ht [ h ] ) ;
array . ht [ h ] = newnp ;
}
2021-10-04 16:14:51 +00:00
/* free(x4a->tbl); // This code was originall written for 16-bit machines.
* * on modern machines , don ' t worry about freeing this trival amount of
* * memory . */
2000-05-29 14:26:00 +00:00
* x4a = array ;
}
/* Insert the new data */
h = ph & ( x4a - > size - 1 ) ;
np = & ( x4a - > tbl [ x4a - > count + + ] ) ;
np - > data = data ;
if ( x4a - > ht [ h ] ) x4a - > ht [ h ] - > from = & ( np - > next ) ;
np - > next = x4a - > ht [ h ] ;
x4a - > ht [ h ] = np ;
np - > from = & ( x4a - > ht [ h ] ) ;
return 1 ;
}
/* Return a pointer to data assigned to the given key. Return NULL
* * if no such key . */
2010-02-14 17:14:22 +00:00
struct config * Configtable_find ( struct config * key )
2000-05-29 14:26:00 +00:00
{
int h ;
x4node * np ;
if ( x4a = = 0 ) return 0 ;
h = confighash ( key ) & ( x4a - > size - 1 ) ;
np = x4a - > ht [ h ] ;
while ( np ) {
2010-02-14 17:14:22 +00:00
if ( Configcmp ( ( const char * ) np - > data , ( const char * ) key ) = = 0 ) break ;
2000-05-29 14:26:00 +00:00
np = np - > next ;
}
return np ? np - > data : 0 ;
}
/* Remove all data from the table. Pass each data to the function "f"
* * as it is removed . ( " f " may be null to avoid this step . ) */
2010-02-14 17:14:22 +00:00
void Configtable_clear ( int ( * f ) ( struct config * ) )
2000-05-29 14:26:00 +00:00
{
int i ;
if ( x4a = = 0 | | x4a - > count = = 0 ) return ;
if ( f ) for ( i = 0 ; i < x4a - > count ; i + + ) ( * f ) ( x4a - > tbl [ i ] . data ) ;
for ( i = 0 ; i < x4a - > size ; i + + ) x4a - > ht [ i ] = 0 ;
x4a - > count = 0 ;
return ;
}