/****************************************************************************** action.c Version 7.20 Semantic actions that are invoked by their index through the call table. Changes the symbol table entry to TYPEDEF_NAME_ when a typedef declaration is recognized. Scopes variables, handling TYPEDEF_NAME_ redefined as an identifier in an inner scope. Copyright (c) 2002-2012 SLK Systems, all rights reserved. ******************************************************************************/ #include "action.h" #include "SlkTable.h" #include "SlkParse.h" // ------------------------------------------------------------------ // actions // // These must be public so they can be entered into the jump table // ------------------------------------------------------------------ void FinishTypedef ( action_t *d ) { symbol_t *last_identifier; last_identifier = get_last_identifier(d->sym); if ( d->typedef_in_progress ) { --d->typedef_in_progress; last_identifier->token = TYPEDEF_NAME_; } else { if ( last_identifier->token == TYPEDEF_NAME_ ) { if ( d->type_specifiers > 0 ) { insert ( d->sym, IDENTIFIER_, last_identifier->name ); } } else { if ( last_identifier->scope < get_table_scope(d->sym) ) { insert ( d->sym, IDENTIFIER_, last_identifier->name ); } } } d->type_specifiers = 0; } void StartTypedef ( action_t *d ) { ++d->typedef_in_progress; } void SetTypedefName ( action_t *d ) { symbol_t *last_identifier; last_identifier = get_last_identifier(d->sym); if ( d->typedef_in_progress ) { last_identifier->token = TYPEDEF_NAME_; } else { if ( last_identifier->token == TYPEDEF_NAME_ ) { if ( d->type_specifiers > 0 ) { insert ( d->sym, IDENTIFIER_, last_identifier->name ); } } else { if ( last_identifier->scope < get_table_scope(d->sym) ) { insert ( d->sym, IDENTIFIER_, last_identifier->name ); } } } d->type_specifiers = 0; } void CountTypeSpecifiers ( action_t *d ) { ++d->type_specifiers; /**** char message [ 128 ]; sprintf ( message, "type_specifiers = %d \n", d->type_specifiers ); trace ( message ); // debugging only ****/ } void NewScope ( action_t *d ) { set_new_table_scope(d->sym); d->type_specifiers = 0; } void ReleaseScope ( action_t *d ) { release_table_scope(d->sym); d->type_specifiers = 0; } /******** void ShowName ( action_t *d ) // debugging only { symbol_t *current; current = get_current(d->sym); sprintf ( message, "%s \n", current->name ); trace ( message ); } ********/ // ------------------------------------------------------------------ // InitializeAction // ------------------------------------------------------------------ PUBLIC void InitializeAction ( action_t *action, int trace, symbols_t *symbols, log_t *log ) { action->trace = trace; action->sym = symbols; action->log = log; action->typedef_in_progress = 0; action->type_specifiers = 0; action->s = SlkActions; } /************************************************************************* action.h Version 7.03 This module contains the public declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #ifndef _SLKACTION_H #define _SLKACTION_H #include "symbol.h" typedef struct _action { log_t *log; symbols_t *sym; int typedef_in_progress; int type_specifiers; int trace; void (**s) ( struct _action * ); } action_t, SlkAction; PUBLIC void InitializeAction ( action_t *action, int trace, symbols_t *symbols, log_t *log ); #endif /***************************************************************************** error.c Version 7.42 Parse error recovery routines. Copyright (c) 2002-2012 SLK Systems, all rights reserved. ******************************************************************************/ #include "error.h" #include "SlkString.h" #include "SlkParse.h" #define GET_SYMBOL_NAME( token ) SlkGetSymbolName ( token ) // ----------------------------------------------------------------------- // mismatch // // Assumes the token is missing, and inserts it. // In special cases like : for ;, replace : with ; instead of inserting. // Scan only if the parser gets stuck in a loop. // // ----------------------------------------------------------------------- INSTANCE_METHOD short (mismatch) ( error_t *d, short terminal, short token ) { char message [ 128 ]; if ( d->mismatch_line_number == get_line_number(d->peek) ) { ++d->mismatch_stuck_count; if ( d->trace ) { sprintf ( message, " mismatch: mismatch_stuck count = %d \n", d->mismatch_stuck_count ); trace ( d->log, message ); } print_error ( d->log, get_line_number(d->peek), "expecting '%s' but found '%s'\n", GET_SYMBOL_NAME (terminal), GET_SYMBOL_NAME (token), 0, 0 ); token = terminal; // insert the token if ( d->mismatch_stuck_count > 99 ) { token = get(d->peek); // advance the input d->mismatch_stuck_count = 0; } } else { if ( ! d->mismatch_stuck_count ) { print_error ( d->log, get_line_number(d->peek), "expecting '%s' but found '%s'\n", GET_SYMBOL_NAME (terminal), GET_SYMBOL_NAME (token), 0, 0 ); switch ( terminal ) { case SEMI_ : if ( token != COLON_ ) { push ( d->peek, get_current(d->sym) ); } break; default : push ( d->peek, get_current(d->sym) ); } token = terminal; // insert the missing token } d->mismatch_stuck_count = 0; } d->mismatch_line_number = get_line_number(d->peek); return token; } // ----------------------------------------------------------------------- // no_entry // // The symbol is a nonterminal. No parse table entry was found. // // The strategy is to try to continue without scanning. If the parser // gets into a loop, then scan. Many of these errors are followed // by a mismatch error that corrects well by insertion or replacement // of the token in the mismatch routine above. // // If the error token is TYPEDEF_NAME_, tell the parser to try again // using IDENTIFIER_. This is an easy way to correct many problems. // See also the action code for more on typedef. // // ----------------------------------------------------------------------- INSTANCE_METHOD short (no_entry) ( error_t *d, short nonterminal, short token, int level ) { char message [ 128 ]; if ( token == TYPEDEF_NAME_ ) { // sprintf ( message, "---- changing TYPEDEF_NAME_ to IDENTIFIER_ \n" ); // trace ( message ); return IDENTIFIER_ ; } if ( d->no_entry_line_number == get_line_number(d->peek) ) { ++d->no_entry_stuck_count; if ( d->trace ) { sprintf ( message, " no_entry: no_entry_stuck count = %d \n", d->no_entry_stuck_count ); trace ( d->log, message ); } if ( d->no_entry_stuck_count > 99 ) { token = get(d->peek); // advance the input d->no_entry_stuck_count = 0; } } else { d->no_entry_stuck_count = 0; } d->no_entry_line_number = get_line_number(d->peek); if ( ! d->no_entry_stuck_count ) { if ( d->trace ) { print_error ( d->log, get_line_number(d->peek), "nonterminal: '%s' token: '%s' (%u)\n", GET_SYMBOL_NAME (nonterminal), GET_SYMBOL_NAME (token), token, 0 ); } else { print_error ( d->log, get_line_number(d->peek), "syntax error\n", 0, 0, 0, 0 ); } } return token; } // ----------------------------------------------------------------------- // input_left // // The parse stack is empty, but input is still remaining. // Usually happens after an improperly recovered error. // // ----------------------------------------------------------------------- INSTANCE_METHOD void (input_left) ( error_t *d ) { if ( get_total_errors(d->log) == 0 || d->trace ) { print_error ( d->log, get_line_number(d->peek), "incomplete parse\n", 0, 0, 0, 0 ); } } // ----------------------------------------------------------------------- // InitializeError // ----------------------------------------------------------------------- PUBLIC void InitializeError ( error_t *error, int trace, symbols_t *symbols, peeker_t *peeker, log_t *log ) { error->trace = trace; error->sym = symbols; error->peek = peeker; error->log = log; error->mismatch_line_number = 0; error->mismatch_stuck_count = 0; error->no_entry_line_number = 0; error->no_entry_stuck_count = 0; error->mismatch = mismatch; error->no_entry = no_entry; error->input_left = input_left; } /************************************************************************** error.h Version 7.30 This file contains the public declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. **************************************************************************/ #ifndef _ERROR_H #define _ERROR_H #include "peeker.h" #undef SELF #define SELF struct _error typedef struct _error { log_t *log; symbols_t *sym; peeker_t *peek; int mismatch_line_number, // avoid duplicate messages no_entry_line_number, mismatch_stuck_count, no_entry_stuck_count, trace; short (*mismatch) ( SELF *id, short symbol, short token ); short (*no_entry) ( SELF *id, short symbol, short token, int level ); void (*input_left) ( SELF *id ); } error_t, SlkError; #define mismatch(self,a,b) (*self).mismatch(self,a,b) #define no_entry(self,a,b,c) (*self).no_entry(self,a,b,c) #define input_left(self) (*self).input_left(self) PUBLIC void InitializeError ( error_t *error, int trace, symbols_t *symbols, peeker_t *peeker, log_t *log ); #endif /*============================================================================= grammar.ll Version 4.51 Full ANSI standard C grammar in EBNF format. Recognizer only. Actions included to handle typedef declaration. Copyright (c) 2001-2012 SLK Systems, all rights reserved. =============================================================================*/ translation_unit : { external_declaration }+ external_declaration : declarator function_definition declaration_specifiers function_or_declaration function_or_declaration : declarator more_function_or_declaration _action_FinishTypedef ; more_function_or_declaration : function_definition [ = initializer ] more_init_declarator_list _action_FinishTypedef ; function_definition : [ declaration_list ] compound_statement declaration : declaration_specifiers [ init_declarator_list ] _action_FinishTypedef ; declaration_list : { declaration }+ declaration_specifiers : storage_class_specifier declaration_specifiers_opt _action_CountTypeSpecifiers type_specifier declaration_specifiers_opt type_qualifier declaration_specifiers_opt declaration_specifiers_opt : declaration_specifiers _epsilon_ storage_class_specifier : auto register static extern typedef _action_StartTypedef type_specifier : void char short int long float double signed unsigned struct_or_union_specifier enum_specifier TYPEDEF_NAME type_qualifier : const volatile struct_or_union_specifier : struct_or_union more_struct_or_union_specifier more_struct_or_union_specifier : IDENTIFIER [ \{ struct_declaration_list \} ] \{ struct_declaration_list \} struct_or_union : struct union struct_declaration_list : { struct_declaration }+ init_declarator_list : init_declarator more_init_declarator_list more_init_declarator_list : _action_SetTypedefName , init_declarator_list _epsilon_ init_declarator : declarator [ = initializer ] struct_declaration : specifier_qualifier_list struct_declarator_list ; specifier_qualifier_list : type_specifier specifier_qualifier_list_opt type_qualifier specifier_qualifier_list_opt specifier_qualifier_list_opt : specifier_qualifier_list _epsilon_ struct_declarator_list : struct_declarator { , struct_declarator } struct_declarator : declarator [ : constant_expression ] : constant_expression enum_specifier : enum more_enum_specifier more_enum_specifier : \{ enumerator_list \} IDENTIFIER [ \{ enumerator_list \} ] enumerator_list : enumerator { , enumerator } enumerator : IDENTIFIER [ = constant_expression ] declarator : [ pointer ] direct_declarator direct_declarator : IDENTIFIER more_direct_declarator ( declarator ) more_direct_declarator more_direct_declarator : \[ constant_expression_opt \] more_direct_declarator _action_NewScope ( parameter_type_list _action_ReleaseScope ) \ more_direct_declarator ( identifier_list_opt ) more_direct_declarator _epsilon_ pointer : * [ type_qualifier_list ] [ pointer ] type_qualifier_list : { type_qualifier }+ parameter_type_list : parameter_list [ , ... ] parameter_type_list_opt : parameter_type_list _epsilon_ parameter_list : parameter_declaration { , parameter_declaration } // conflict parameter_declaration : declaration_specifiers [ declarator_or_abstract_declarator ] declarator_or_abstract_declarator : direct_declarator_or_direct_abstract_declarator pointer [ direct_declarator_or_direct_abstract_declarator ] direct_declarator_or_direct_abstract_declarator : IDENTIFIER more_dd_or_dad ( declarator_or_abstract_declarator ) more_dd_or_dad \[ constant_expression_opt \] more_dd_or_dad ( parameter_type_list_opt ) more_dd_or_dad more_dd_or_dad : \[ constant_expression_opt \] more_dd_or_dad ( parameter_type_list ) more_dd_or_dad ( identifier_list_opt ) more_dd_or_dad _epsilon_ identifier_list : IDENTIFIER { , IDENTIFIER } identifier_list_opt : identifier_list _epsilon_ initializer : assignment_expression \{ initializer_list [ , ] \} initializer_list : initializer { , initializer } // conflict type_name : specifier_qualifier_list [ abstract_declarator ] abstract_declarator : pointer [ direct_abstract_declarator ] direct_abstract_declarator direct_abstract_declarator : ( abstract_declarator ) more_direct_abstract_declarator \[ constant_expression_opt \] more_direct_abstract_declarator ( parameter_type_list_opt ) more_direct_abstract_declarator more_direct_abstract_declarator : \[ constant_expression_opt \] more_direct_abstract_declarator ( parameter_type_list_opt ) more_direct_abstract_declarator _epsilon_ statement : labeled_statement // conflict expression_statement // conflict compound_statement selection_statement iteration_statement jump_statement labeled_statement : IDENTIFIER : statement case constant_expression : statement default : statement expression_statement : expression_opt ; compound_statement : _action_NewScope \{ [ declaration_list ] statement_list_opt \ _action_ReleaseScope \} statement_list_opt : statement_list _epsilon_ statement_list : { statement }+ selection_statement : if ( expression ) statement [ else statement ] // conflict switch ( expression ) statement iteration_statement : while ( expression ) statement do statement while ( expression ) ; for ( expression_opt ; expression_opt ; expression_opt ) statement jump_statement : goto IDENTIFIER ; continue ; break ; return expression_opt ; expression_opt : expression _epsilon_ expression : assignment_expression { , assignment_expression } /* ----------------------------------------------------------------------- use semantic check for lvalue instead of the following production: unary_expression assignment_operator assignment_expression ----------------------------------------------------------------------- */ assignment_expression : conditional_expression [ assignment_operator assignment_expression ] assignment_operator : = *= /= %= += -= <<= >>= &= ^= |= conditional_expression : logical_OR_expression [ ? expression : conditional_expression ] constant_expression : conditional_expression constant_expression_opt : constant_expression _epsilon_ logical_OR_expression : logical_AND_expression { || logical_AND_expression } logical_AND_expression : inclusive_OR_expression { && inclusive_OR_expression } inclusive_OR_expression : exclusive_OR_expression { | exclusive_OR_expression } exclusive_OR_expression : and_expression { ^ and_expression } and_expression : equality_expression { & equality_expression } equality_expression : relational_expression { equality_op relational_expression } equality_op : == != relational_expression : shift_expression { relational_op shift_expression } relational_op : < > <= >= shift_expression : additive_expression { shift_op additive_expression } shift_op : << >> additive_expression : multiplicitive_expression { additive_op multiplicitive_expression } additive_op : + - multiplicitive_expression : cast_expression { multiplicitive_op cast_expression } multiplicitive_op : * / % cast_expression : // conflict unary_expression ( type_name ) cast_expression unary_expression : postfix_expression ++ unary_expression -- unary_expression unary_operator cast_expression sizeof more_sizeof more_sizeof : unary_expression // conflict ( type_name ) unary_operator : & * + - ~ ! postfix_expression : primary_expression more_postfix_expression more_postfix_expression : \[ expression \] more_postfix_expression ( [ argument_expression_list ] ) more_postfix_expression . IDENTIFIER more_postfix_expression -> IDENTIFIER more_postfix_expression ++ more_postfix_expression -- more_postfix_expression _epsilon_ primary_expression : IDENTIFIER // _action_ShowName constant STRING ( expression ) argument_expression_list : assignment_expression { , assignment_expression } constant : INTEGER_CONSTANT CHARACTER_CONSTANT FLOATING_CONSTANT ENUMERATION_CONSTANT /************************************************************************* list.c Version 7.40 This module contains the public list_node declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #include #include #include "list.h" // ----------------------------------------------------------------------- // get_first // ----------------------------------------------------------------------- INSTANCE_METHOD item_t (get_first) ( list_t *d ) { return d->list [ d->current = 0 ]; } // ----------------------------------------------------------------------- // get_next // ----------------------------------------------------------------------- INSTANCE_METHOD item_t (get_next) ( list_t *d ) { if ( d->current <= d->last ) { return d->list [ d->current++ ]; } else { return NULL; } } // ----------------------------------------------------------------------- // append // ----------------------------------------------------------------------- INSTANCE_METHOD void (append) ( list_t *d, item_t item ) { if ( d->last >= d->max ) { d->list = (item_t *) realloc ( d->list, (d->max + 1 + d->chunk) * sizeof ( item_t )); if ( ! d->list ) { puts ("list_t: out of memory"); exit(1); } d->max += d->chunk - 1; } d->list [ d->last++ ] = item; } // ----------------------------------------------------------------------- // show_all // ----------------------------------------------------------------------- INSTANCE_METHOD void (show_all) ( list_t *d ) { int i; for ( i = 0; i < d->last; ++i ) { puts ( d->list[i]->name ); } } // ----------------------------------------------------------------------- // release // ----------------------------------------------------------------------- INSTANCE_METHOD void (release) ( list_t *d ) { free ( d->list ); } // ----------------------------------------------------------------------- // InitializeList // ----------------------------------------------------------------------- PUBLIC void InitializeList ( list_t *list ) { int chunk = 64 * 1024; list->current = 0; list->last = 0; list->chunk = chunk; list->max = chunk - 1; list->list = (item_t *) malloc ( chunk * sizeof ( item_t ) ); list->get_first = get_first; list->get_next = get_next; list->append = append; list->show_all = show_all; list->release = release; } /************************************************************************* list.h Version 7.30 This module contains the public list_node declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #ifndef _LIST_H #define _LIST_H #include "symbol.h" #define PRIVATE static #define PUBLIC #define INSTANCE_METHOD static // ------------------------------------------------------------------------ // list_t // // A pseudo-class to avoid global function names and enable initialization. // reentrant. // ------------------------------------------------------------------------ typedef symbol_t * item_t; #undef SELF #define SELF struct _list typedef struct _list { item_t *list; int current; int last; int max; int chunk; item_t (*get_first) ( SELF * ); item_t (*get_next) ( SELF * ); void (*append) ( SELF *, item_t item ); void (*show_all) ( SELF * ); void (*release) ( SELF * ); } list_t; #define get_first(self) (*self).get_first(self) #define get_next(self) (*self).get_next(self) #define append(self,a) (*self).append(self, a) #define show_all(self) (*self).show_all(self) #define release(self) (*self).release(self) PUBLIC void InitializeList ( list_t *list ); #endif /***************************************************************************** log.c Version 7.42 This module contains the error logging methods Copyright (c) 2002-2012 SLK Systems, all rights reserved. ******************************************************************************/ #include "log.h" #include "SlkString.h" // ------------------------------------------------------------------------ // get_file // // returns the file in a malloc buffer. // file is null terminated // ------------------------------------------------------------------------ PRIVATE char * get_file ( char *file_name ) { size_t file_size, size; FILE *fp; char *file = NULL; fp = fopen ( file_name, "rb" ); if ( fp ) { fseek ( fp, 0L, 2 ); file_size = ftell ( fp ); rewind ( fp ); file = (char *) malloc ( file_size + 4 ); if ( file ) { size = fread ( file, 1, file_size, fp ); if ( size == file_size ) { file [ file_size ] = '\0'; file [ file_size + 1 ] = '\0'; } else { free ( file ); file = NULL; } } fclose ( fp ); } return file; } // ------------------------------------------------------------------------ // for SlkParse // ------------------------------------------------------------------------ #ifdef UNIT_TEST #define GET_PRODUCTION_NAME(a) "unit testing" #define GET_SYMBOL_NAME(a) "unit testing" #else #define GET_PRODUCTION_NAME SlkGetProductionName #define GET_SYMBOL_NAME SlkGetSymbolName #endif INSTANCE_METHOD void (trace) ( log_t *d, char *message ) { fputs ( message, d->fp ); } INSTANCE_METHOD void (trace_depth) ( log_t *d, char *message, int depth ) { int i; for ( i = 0; i < depth; ++i ) { fputs ( " ", d->fp ); } fputs ( message, d->fp ); } INSTANCE_METHOD void (trace_production) ( log_t *d, int production_number ) { fputs ( GET_PRODUCTION_NAME ( production_number ), d->fp ); fputs ( "\n", d->fp ); } INSTANCE_METHOD void (trace_action) ( log_t *d, int action_number ) { fputs ( "\n", d->fp ); fputs ( GET_SYMBOL_NAME ( action_number ), d->fp ); fputs ( "\n\n", d->fp ); } // ------------------------------------------------------------------------ // print_warning // ------------------------------------------------------------------------ INSTANCE_METHOD void (print_warning) ( log_t *d, int line_number, char *format, void *arg1, void *arg2, void *arg3, void *arg4 ) { ++d->total_warnings; if ( d->fp != stdout ) { fprintf ( stderr, "%s:%u: ", d->input_file_name, line_number ); fprintf ( stderr, format, arg1, arg2, arg3, arg4 ); } fprintf ( d->fp, "%s:%u: ", d->input_file_name, line_number ); fprintf ( d->fp, format, arg1, arg2, arg3, arg4 ); if ( d->total_warnings > d->max_total_warnings ) { fprintf ( stderr, "maximum total warnings exceeded \n" ); exit ( d->total_warnings ); } } // ------------------------------------------------------------------------ // print_error // ------------------------------------------------------------------------ INSTANCE_METHOD void (print_error) ( log_t *d, int line_number, char *format, void *arg1, void *arg2, void *arg3, void *arg4 ) { ++d->total_errors; if ( d->fp != stdout ) { fprintf ( stderr, "%s:%u: ", d->input_file_name, line_number ); fprintf ( stderr, format, arg1, arg2, arg3, arg4 ); } fprintf ( d->fp, "%s:%u: ", d->input_file_name, line_number ); fprintf ( d->fp, format, arg1, arg2, arg3, arg4 ); if ( d->total_errors > d->max_total_errors ) { fprintf ( stderr, "maximum total errors exceeded \n" ); exit ( d->total_errors ); } } // ----------------------------------------------------------------------- // release // ----------------------------------------------------------------------- INSTANCE_METHOD void (release) ( log_t *d ) { if ( d->fp ) { if ( d->fp != stdout && d->fp != stderr ) { fclose ( d->fp ); } } free ( d->input_text ); } // ------------------------------------------------------------------------ // InitializeLog // // C scoping takes care of the struct itself, // only need to release to close files or free malloced memory // ------------------------------------------------------------------------ PUBLIC void InitializeLog ( log_t *log, char *log_file_name, char *input_file_name ) { log->log_file_name = log_file_name; log->input_file_name = input_file_name; log->total_warnings = 0; log->total_errors = 0; log->max_total_warnings = 500; log->max_total_errors = 100; if ( log->log_file_name ) { log->fp = fopen ( log->log_file_name, "w" ); } else { log->fp = stdout; log->log_file_name = "stdout"; } if ( ! log->fp ) { log->fp = stdout; log->log_file_name = "stdout"; } log->input_text = get_file ( input_file_name ); if ( ! log->input_text ) { perror ( input_file_name ); exit (1); } log->trace = trace; log->trace_depth = trace_depth; log->trace_production = trace_production; log->trace_action = trace_action; log->print_warning = print_warning; log->print_error = print_error; log->release = release; } // ======================================================================= // #define UNIT_TEST to exercise this module // ======================================================================= #ifdef UNIT_TEST int by_ref ( log_t *log ) { int rc = 0; print_error ( log, 325, "%s %d\n", "errors", get_total_errors(log), 0,0 ); print_error ( log, 327, "%s %d\n", "errors", get_total_errors(log), 0,0 ); print_error ( log, 329, "%s %d\n", "errors", get_total_errors(log), 0,0 ); printf ( "log: %d\n", log ); release ( log ); printf ( "release log: %d\n", log ); InitializeLog ( log, 0, "log.h" ); printf ( "new log: %d\n", log ); print_error ( log, 337, "%s %d\n", "errors", get_total_errors(log), 0,0 ); return rc; } int main ( int argc, char *argv[] ) { int rc = 0; log_t log; InitializeLog ( &log, 0, "log.h" ); print_error ( &log, 375, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); print_error ( &log, 377, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); print_error ( &log, 379, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); release ( &log ); printf ( "old log: %d\n", &log ); InitializeLog ( &log, 0, "log.h" ); printf ( "new log: %d\n", &log ); print_error ( &log, 386, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); print_error ( &log, 390, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); print_error ( &log, 392, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); print_error ( &log, 394, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); release ( &log ); printf ( "old log: %d\n", &log ); InitializeLog ( &log, 0, "log.h" ); printf ( "new log: %d\n", &log ); print_error ( &log, 386, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); by_ref ( &log ); print_error ( &log, 398, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); print_error ( &log, 400, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); print_error ( &log, 402, "%s %d\n", "errors", get_total_errors(&log), 0,0 ); return rc; } #endif /***************************************************************************** log.h Version 7.42 This module contains the error logging declarations Copyright (c) 2002-2012 SLK Systems, all rights reserved. ******************************************************************************/ #ifndef _LOG_T_H #define _LOG_T_H #include #include #define TRUE 1 #define FALSE 0 #define PUBLIC #define PRIVATE static #define INSTANCE_METHOD static // ------------------------------------------------------------------------ // log_t // // A struct to avoid public names, enable initialization, and // provide instance data so it is reentrant. // The struct only goes away when its declaration goes out of scope. // Any cleanup should be in release. // ------------------------------------------------------------------------ #undef SELF #define SELF struct _log typedef struct _log { int total_warnings, total_errors, max_total_warnings, max_total_errors; char *input_file_name; char *input_text; FILE *fp; char *log_file_name; void (*trace ) ( SELF *id, char *message ); void (*trace_depth ) ( SELF *id, char *message, int depth ); void (*trace_production ) ( SELF *id, int production_number ); void (*trace_action ) ( SELF *id, int action_number ); void (*print_warning ) ( SELF *id, int line_number, char *format, void *arg1, void *arg2, void *arg3, void *arg4 ); void (*print_error ) ( SELF *id, int line_number, char *format, void *arg1, void *arg2, void *arg3, void *arg4 ); void (*release ) ( SELF *id ); } log_t, SlkLog; #define set_max_errors(self,a) ((*self).max_total_errors = a) #define set_max_warnings(self,a) ((*self).max_total_warnings = a) #define get_total_errors(self) ((*self).total_errors) #define get_total_warnings(self) ((*self).total_warnings) #define get_input_text(self) ((*self).input_text) #define get_input_file_name(self) ((*self).input_file_name) #define trace(self,a) (*self).trace(self,a) #define trace_depth(self,a,b) (*self).trace_depth(self,a,b) #define trace_production(self,a) (*self).trace_production(self,a) #define trace_action(self,a) (*self).trace_action(self,a) #define release(self) (*self).release(self) #ifdef _USE_LOG_PRINT_FUNCTIONS #define print_warning(self,a,b,c,d,e,f,g) (*self).print_warning(self,a,b,c,d,e,f,g) #define print_error(self,a,b,c,d,e,f) (*self).print_error(self,a,b,c,d,e,f) #else #define print_warning(self,line,fmt,c,d,e,f) ++(*self).total_warnings; \ fprintf((*self).fp, "%s:%u: ",(*self).input_file_name,line); \ fprintf((*self).fp,fmt,c,d,e,f); \ if ((*self).total_warnings > (*self).max_total_warnings){ \ fprintf(stderr, "maximum total warnings exceeded\n"); \ exit((*self).total_warnings); \ } #define print_error(self,line,fmt,c,d,e,f) ++(*self).total_errors; \ fprintf((*self).fp, "%s:%u: ",(*self).input_file_name,line); \ fprintf((*self).fp,fmt,c,d,e,f); \ if ((*self).total_errors > (*self).max_total_errors){ \ fprintf(stderr, "maximum total errors exceeded\n"); \ exit((*self).total_errors); \ } #endif PUBLIC void InitializeLog ( log_t *log, char *log_file_name, char *input_file_name ); #endif /************************************************************************* main.c Version 7.40 Main entry point for the C recognizer. Copyright (c) 2001-2012 SLK Systems, all rights reserved. 04-24-12 removed log.get_buffer, use local message[] 05-08-12 Switched to Initialize struct from Make struct in all, problems with returning the contructed struct by value 05-23-12 Switched to by reference for all structs, (*log).trace 05-31-12 Removed all #undef method, use () instead *************************************************************************/ #include #include #include "SlkParse.h" #define DISPLAY 0x00000001 #define NAMETABLE 0x00000002 #define SHOW_DERIVATION 0x00000010 #define SHOW_PARSE_TREE 0x00000020 #define SHOW_SYMBOLS_LIST 0x00000040 #define TRACE_ERRORS 0x00010000 #define TRACE_LOAD 0x00020000 #define TRACE_NAMES 0x00040000 #define TRACE_PEEKER 0x00080000 #define TRACE_SYMBOLS 0x00100000 #define TRACE_ALL ( TRACE_ERRORS | TRACE_LOAD | TRACE_NAMES | \ TRACE_PEEKER | TRACE_SYMBOLS ) #define HASH_SIZE 1013 // prime number: 211 503 1013 10007 40013 PRIVATE char Banner [] = "scc V7.40 (c) 2001-2012 SLK Systems"; PRIVATE char UsageMessage [] = "C language compiler\n" "Usage: scc file_name [ options ]\n\n" " -a turn on all options that have no argument \n" " -d display parse derivation while parsing \n" " -l set log file name, default=stdout \n" " -p print symbol table \n" " -Men set maximum allowed errors to n \n" " -Mwn set maximum allowed warnings to n \n" " -Sd show parse derivation from parse tree \n" " -Ss show all symbols list \n" " -St show parse tree \n" " -Te trace error handling \n" " -Tn trace names after they are returned from the scanner \n" " -Tp trace peeking/scanning of tokens \n" " -Ts trace symbol lookup/installation \n" " -Ta trace all \n"; // ------------------------------------------------------------------------ // main // ------------------------------------------------------------------------ PUBLIC int main ( int argc, char *argv [] ) { register char *p, *log_file_name = NULL, *file_name = NULL; int errors = 0, warnings = 0, options = 0; log_t log; symbols_t sym; peeker_t peeker; error_t error; action_t action; tree_t tree; list_t list; // all symbols in order of scanning char message [ 128 ]; puts ( Banner ); while ( --argc > 0 ) { // process command line options p = *++argv; switch (*p){ case '/': case '-': if ( *++p ) { switch ( *p ) { case 'a': options = -1; break; case 'd': options |= DISPLAY; break; case 'l': if ( *++p ) { log_file_name = p; } break; case 'p': options |= NAMETABLE; break; case 'M': if ( *++p ) { switch ( *p ) { case 'e': errors = atoi ( ++p ); break; case 'w': warnings = atoi ( ++p ); break; default: fputc ('M', stderr); fputc (*p, stderr); fputs (", invalid option\n", stderr); } } break; case 'S': while ( *++p ) { switch ( *p ) { case 'd': options |= SHOW_DERIVATION; break; case 's': options |= SHOW_SYMBOLS_LIST; break; case 't': options |= SHOW_PARSE_TREE; break; default: fputc ('S', stderr); fputc (*p, stderr); fputs (", invalid option\n", stderr); } } --p; break; case 'T': while ( *++p ) { switch ( *p ) { case 'a': options |= TRACE_ALL; break; case 'e': options |= TRACE_ERRORS; break; case 'n': options |= TRACE_NAMES; break; case 'p': options |= TRACE_PEEKER; break; case 's': options |= TRACE_SYMBOLS; break; default: fputc ('T', stderr); fputc (*p, stderr); fputs (", invalid option\n", stderr); } } --p; break; default: fputc (*p, stderr); fputs (", invalid option\n", stderr); } } break; default: file_name = *argv; } } if ( ! file_name ) { puts ( UsageMessage ); exit (1); } InitializeLog ( &log, log_file_name, file_name ); if ( errors ) { set_max_errors ( &log, errors ); } if ( warnings ) { set_max_warnings ( &log, warnings ); } InitializeList ( &list ); InitializeSymbols ( &sym, (options & TRACE_SYMBOLS), HASH_SIZE, &log ); InitializePeeker ( &peeker, (options & TRACE_PEEKER), &sym, &log, &list ); InitializeError ( &error, (options & TRACE_ERRORS), &sym, &peeker, &log); InitializeAction ( &action, (options & TRACE_NAMES), &sym, &log ); InitializeTree ( &tree, (options & TRACE_NAMES), &log, &sym, &list ); SlkParse ( (options & DISPLAY), &action, &peeker, &error, &log, &tree, 0 ); warnings = get_total_warnings ( &log ); errors = get_total_errors ( &log ); if ( warnings ) { sprintf ( message, "%5u warnings \n", warnings ); trace ( &log, message ); } if ( errors ) { sprintf ( message, "%5u errors \n", errors ); trace ( &log, message ); } if ( options & NAMETABLE ) { print_table ( &sym ); } if ( ! errors ) { prune ( &tree ); add_symbols ( &tree ); if ( options & SHOW_SYMBOLS_LIST ) { show_all ( &list ); } if ( options & SHOW_DERIVATION ) { show_parse_derivation ( &tree ); } if ( options & SHOW_PARSE_TREE ) { show_tree ( &tree ); } } return errors; } # =================================================================== # # makefile for scc # # works for windows-32 and gnu unix # # =================================================================== OUT = scc TEMP_HEADERS = SlkLog.h SlkToken.h SlkError.h SlkAction.h SlkTree.h LOCAL_HEADERS = log.h peeker.h error.h action.h tree.h list.h HEADER_FILES = symbol.h scanner.h memory.h SlkParse.h SlkTable.h \ $(TEMP_HEADERS) $(LOCAL_HEADERS) SLK_FILES = SlkParse.h SlkParse.cpp SlkTable.h SlkTable.cpp GNU_OBJS = scanner.o memory.o symbol.o tree.o list.o main.o \ log.o peeker.o error.o action.o \ SlkString.o SlkParse.o SlkTable.o OBJS = scanner.obj memory.obj symbol.obj tree.obj list.obj main.obj \ log.obj peeker.obj error.obj action.obj \ SlkString.obj SlkParse.obj SlkTable.obj # ------------------------------------------------------------------- # windows compiler flags and defines - ibm # ------------------------------------------------------------------- IBM_CC = icc -c IBM_LINK = ilink IBM_DBG_CFLAGS = -O- -Ti+ -DDEBUG IBM_DBG_LFLAGS = -debug IBM_CFLAGS = $(CINC) -Q+ -O+ -G5 -Wuse+ $(DBG_CFLAGS) IBM_LFLAGS = /map /nologo /out:$(OUT) $(DBG_LFLAGS) # ------------------------------------------------------------------- # windows compiler flags and defines - watcom # problem with WAT_DBG_LFLAGS quotes, so do it differently # ------------------------------------------------------------------- WAT_CC = wcl386 -c WAT_LINK = wcl386 WAT_CFLAGS = $(CINC) -zq -wx -6r -fp6 -Ox WAT_DBG_CFLAGS = $(CINC) -zq -wx -6r -fp6 -Od -d2 -DDEBUG WAT_LFLAGS = -x -k32K -fm -zq -fe=$(OUT) WAT_DBG_LFLAGS = -"DEBUG ALL" # ------------------------------------------------------------------- # gnu compiler flags and defines # ------------------------------------------------------------------- GNU_CC = gcc -c GNU_LINK = gcc GNU_CFLAGS = $(CINC) $(DBG_CFLAGS) GNU_LFLAGS = -o$(OUT) GNU_DBG_CFLAGS = -g -DDEBUG GNU_DBG_LFLAGS = # ------------------------------------------------------------------- # inference rules: # ------------------------------------------------------------------- .c.o: $(CC) $(CFLAGS) $*.c .c.obj: $(CC) $(CFLAGS) $*.c # ------------------------------------------------------------------- # dependancies: # ------------------------------------------------------------------- all: @$(MAKE) -nologo help # ------------------------------------------------------------------- ibm: @$(MAKE) -nologo "CC=$(IBM_CC)" "CFLAGS=$(IBM_CFLAGS)$(FLAG)" ibmprog ibmdbg: @$(MAKE) -nologo "DBG_LFLAGS=$(IBM_DBG_LFLAGS)" "DBG_CFLAGS=$(IBM_DBG_CFLAGS)$(FLAG)" ibm ibmprog: $(OBJS) $(IBM_LINK) $(IBM_LFLAGS) $** # ------------------------------------------------------------------- wat: @$(MAKE) -nologo "CC=$(WAT_CC)" "CFLAGS=$(WAT_CFLAGS)" "FLAG=$(FLAG)" watprog watprog: $(OBJS) $(WAT_LINK) $(WAT_LFLAGS) $** watdbg: @$(MAKE) -nologo "CC=$(WAT_CC)" "CFLAGS=$(WAT_DBG_CFLAGS)" "FLAG=$(FLAG)" watdbgprog watdbgprog: $(OBJS) $(WAT_LINK) $(WAT_LFLAGS) -"DEBUG ALL" $** # ------------------------------------------------------------------- gnu: @$(MAKE) "CC=$(GNU_CC)" "CFLAGS=$(GNU_CFLAGS)$(FLAG)" gnuprog gnudbg: @$(MAKE) "DBG_LFLAGS=$(GNU_DBG_LFLAGS)" "DBG_CFLAGS=$(GNU_DBG_CFLAGS)$(FLAG)" gnu gnuprog: $(GNU_OBJS) $(GNU_LINK) $(GNU_LFLAGS) $(GNU_OBJS) # ------------------------------------------------------------------- clean: rm -f *.o rm -f *.obj rm -f *.lst rm -f *.err rm -f *.map rm -f *.def rm -f *.exe rm -f *.out rm -f Slk*.* rm -f $(OUT) rm -f xxx* test: for %%f in (..\c\test\*.c) do scc %%f help: @echo Usage: make gnu or gnudbg (gnu or debug-gnu target) @echo make ibm or ibmdbg @echo make msc or mscdbg @echo make target "FLAG=-w3" (add C compile flags) @echo make clean (clean directory files) $(OBJS): $(HEADER_FILES) $(GNU_OBJS): $(HEADER_FILES) SlkLog.h: log.h copy /Y log.h SlkLog.h SlkToken.h: peeker.h copy /Y peeker.h SlkToken.h SlkError.h: error.h copy /Y error.h SlkError.h SlkAction.h: action.h copy /Y action.h SlkAction.h SlkTree.h: tree.h copy /Y tree.h SlkTree.h deltemp: del /Q SlkLog.* del /Q SlkToken.* del /Q SlkError.* del /Q SlkAction.* del /Q SlkTree.* $(SLK_FILES): grammar.ll makefile slk -i -v -cc -g grammar.ll > slk.out tail -n20 slk.out /************************************************************************* memory.c Version 7.41 This module contains the public memory declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #include #include #include #include "memory.h" // ----------------------------------------------------------------------- // set_new_chunk // // allocate another chunk of memory to the struct, zeroed out // ----------------------------------------------------------------------- PRIVATE void set_new_chunk ( memory_t *d ) { void **next, **last = d->memory; int chunk = d->chunk; size_t size = sizeof ( double ); next = calloc ( (chunk / size), size ); // double boundary if ( ! next ) { puts ("memory_t: out of memory"); exit(1); } d->start = sizeof ( void * ); // leave room for "next" pointer d->memory = next; *last = next; // point to this chunk } // ----------------------------------------------------------------------- // allocate // // return pointer to allocated memory of length size, zeroed out // ----------------------------------------------------------------------- INSTANCE_METHOD void * (allocate) ( memory_t *d, int size ) { void *new_item; if ( size > d->chunk - sizeof ( void * ) ) { printf ( "memory_t: max memory chunk size is %d bytes\n", d->chunk - sizeof ( void * ) ); exit(1); // UT } if ( d->start + size > d->end ) { set_new_chunk ( d ); } new_item = (char *) d->memory + d->start; d->start += size; return new_item; } // ----------------------------------------------------------------------- // save // // save item of length size in memory, return pointer to it // ----------------------------------------------------------------------- INSTANCE_METHOD void * (save) ( memory_t *d, void *item, int size ) { void *new_item; if ( size > d->chunk - sizeof ( void * ) ) { printf ( "memory_t: max memory chunk size is %d bytes\n", d->chunk - sizeof ( void * ) ); exit(1); // UT } if ( d->start + size > d->end ) { set_new_chunk ( d ); } new_item = (char *) d->memory + d->start; memcpy ( new_item, item, size ); d->start += size; return new_item; } // ----------------------------------------------------------------------- // release // ----------------------------------------------------------------------- INSTANCE_METHOD void (release) ( memory_t *d ) { register void **next = d->first_chunk; void *memory; while ( next ) { memory = next; next = *next; // UT printf ( " free chunk %x\n", memory ); free ( memory ); } } // ----------------------------------------------------------------------- // InitializeMemory // ----------------------------------------------------------------------- PUBLIC void InitializeMemory ( register memory_t *memory ) { register void **next; size_t size = sizeof ( double ); int chunk = 64 * 1024; // UT = 64 memory->start = sizeof ( void * ); // next pointer is first bytes memory->chunk = chunk; memory->end = chunk - 1; next = calloc ( (chunk / size), size ); // double boundary if ( ! next ) { puts ("memory_t: no memory available"); exit(1); } memory->first_chunk = next; memory->memory = next; memory->allocate = allocate; memory->save = save; memory->release = release; } // ======================================================================= // UNIT_TEST methods to exercise this module // ======================================================================= #ifdef UNIT_TEST int main ( int argc, char *argv[] ) { // remember to change chunk to just 64 int rc = 0, i, j; char *new_string; char *string = "123456789 123456789 123456789 123456789 123456789"; int size = strlen ( string ) + 1; memory_t mem; for ( j = 0; j < 5; ++j ) { InitializeMemory ( &mem ); for ( i = 0; i < 65; ++i ) { new_string = save ( &mem, string, size ); puts ( new_string ); } allocate ( &mem, 60 ); allocate ( &mem, 61 ); // test for size too big release ( &mem ); size -= 10; } return rc; } #endif /************************************************************************* memory.h Version 7.30 This module contains the public memory declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #ifndef _MEMORY_H #define _MEMORY_H #define PRIVATE static #define PUBLIC #define INSTANCE_METHOD static // ------------------------------------------------------------------------ // memory_t // // A pseudo-class to avoid global function names and enable initialization. // reentrant. // ------------------------------------------------------------------------ #undef SELF #define SELF struct _memory typedef struct _memory { void *memory; void *first_chunk; int start; int end; int chunk; void * (*allocate) ( SELF *id, int size ); void * (*save) ( SELF *id, void *, int ); void (*release) ( SELF *id ); } memory_t; #define allocate(self,a) (*self).allocate(self,a) #define save(self,a,b) (*self).save(self,a,b) #define release(self) (*self).release(self) PUBLIC void InitializeMemory ( memory_t *memory ); #endif /***************************************************************************** peeker.c Version 7.42 Interface to the actual lexical scanner for the compiler. This is needed to provide the peeking capability for the LL(k) parser. Doing it here rather than in the parser means that the parser is independent of the symbol table and any other attributes that may be used. This also allows the use of other scanners or generated scanners. Copyright (c) 2002-2012 SLK Systems, all rights reserved. ******************************************************************************/ #include "peeker.h" #include "SlkString.h" #define GET_SYMBOL_NAME( token ) SlkGetSymbolName ( token ) // ----------------------------------------------------------------------- // get // // scan next token // ----------------------------------------------------------------------- INSTANCE_METHOD short (get) ( peeker_t *d ) { short token; char message [ 128 ]; if ( d->pk.count ) { // previous peek_token token = (*d->pk.current)->token; set_current ( d->sym, *d->pk.current ); if ( --d->pk.count == 0 ) { // peek buffer empty d->pk.current = d->pk.buffer; } else { ++d->pk.current; } #ifdef TRACE_3 sprintf ( message, " d->pk.count = %d Peek offset = %u \n", d->pk.count, d->pk.current - d->pk.buffer ); trace ( d->log, message ); #endif } else { token = get ( &d->scan ); } if ( d->trace ) { sprintf ( message," get_token(%u): '%s' \n", d->pk.count + 1, GET_SYMBOL_NAME (token)); trace ( d->log, message ); } return token; } // ----------------------------------------------------------------------- // peek // // scan next token without consuming it // ----------------------------------------------------------------------- INSTANCE_METHOD short (peek) ( peeker_t *d, int level ) { short token; symbol_t *save_symbol; char message [ 128 ]; if ( level > d->pk.count ) { save_symbol = get_current(d->sym); token = get ( &d->scan ); d->pk.current[d->pk.count] = get_current(d->sym); if ( ++d->pk.count >= PEEK_STACK_SIZE ) { --d->pk.count; sprintf ( message, " peek_token(%u): " "Peek stack overflow \n" , level ); trace ( d->log, message ); } set_current ( d->sym, save_symbol ); } token = d->pk.current [ level - 1 ]->token; #ifdef TRACE_3 sprintf ( message, " d->pk.count = %d Peek offset = %u \n", d->pk.count, d->pk.current - d->pk.buffer ); trace ( d->log, message ); #endif if ( d->trace ) { sprintf ( message," peek_token(%u): '%s' \n", level, GET_SYMBOL_NAME (token)); trace ( d->log, message ); } return token; } // ----------------------------------------------------------------------- // push // // put a token/symbol back on the input queue // ----------------------------------------------------------------------- INSTANCE_METHOD void (push) ( peeker_t *d, symbol_t *symbol ) { char message [ 128 ]; if ( d->pk.count ) { --d->pk.count; // just back up one } else { *d->pk.current = symbol; ++d->pk.count; } if ( d->trace ) { sprintf ( message," push_token(%u): '%s' \n", d->pk.count + 1, symbol->name ); trace ( d->log, message ); } } // ----------------------------------------------------------------------- // get_line_number // // return line_number from scanner_t // ----------------------------------------------------------------------- INSTANCE_METHOD int (get_line_number) ( peeker_t *d ) { return d->scan.line_number; } // ----------------------------------------------------------------------- // InitializePeeker // // inherits scanner_t // list not used here, just passed thru to scanner; scan<->list<->tree // ----------------------------------------------------------------------- PUBLIC void InitializePeeker ( peeker_t *peeker, int trace, symbols_t *symbols, log_t *log, list_t *list ) { InitializeScanner ( &peeker->scan, trace, symbols, log, list ); peeker->log = log; peeker->sym = symbols; peeker->pk.current = peeker->pk.buffer; peeker->pk.count = 0; peeker->trace = trace; peeker->get_line_number = get_line_number; peeker->push = push; peeker->get = get; peeker->peek = peek; } /************************************************************************** peeker.h Version 7.42 This file contains the public declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. **************************************************************************/ #ifndef _PEEKER_H #define _PEEKER_H #include "scanner.h" // ------------------------------------------------------------------------ // peeker_t // // A pseudo-class to avoid global function names and enable initialization. // reentrant. // ------------------------------------------------------------------------ #define PEEK_STACK_SIZE 128 typedef struct _peek { symbol_t *buffer [ PEEK_STACK_SIZE ], **current; int count; } peek_t; #undef SELF #define SELF struct _peeker typedef struct _peeker { log_t *log; symbols_t *sym; scanner_t scan; // inherited instance peek_t pk; int trace; void (*push) ( SELF *d, symbol_t *symbol ); short (*peek) ( SELF *d, int level ); short (*get) ( SELF *d ); int (*get_line_number) ( SELF *d ); } peeker_t, SlkToken; #undef get_line_number #define push(self,a) (*self).push(self, a) #define peek(self,a) (*self).peek(self, a) #define get(self) (*self).get(self) #define get_line_number(self) (*self).get_line_number(self) PUBLIC void InitializePeeker ( peeker_t *peeker, int trace, symbols_t *symbols, log_t *log, list_t *list ); #endif /***************************************************************************** scanner.c Version 7.42 Hand coded lexical scanner for the compiler. Copyright (c) 2002-2012 SLK Systems, all rights reserved. ******************************************************************************/ #include #include "scanner.h" #include "SlkParse.h" // ------------------------------------------------------------------------ // install_name // // install without duplicates, return token // local only // ------------------------------------------------------------------------ PRIVATE short install_name ( scanner_t *d, char *start, register char *end, short token ) { register symbol_t *symbol; char save; if ( token == END_OF_SLK_INPUT_ ) { return token; } save = *end; *end = '\0'; if ( ! *start ) { print_error ( d->log, d->line_number, "scanner_t: zero length identifier\n", 0, 0, 0, 0 ); } symbol = lookup ( d->sym, start ); if ( ! symbol ) { symbol = insert ( d->sym, token, start ); } append ( d->list, symbol ); *end = save; return symbol->token; } // ------------------------------------------------------------------------ // get // // return a token // ------------------------------------------------------------------------ INSTANCE_METHOD short (get) ( scanner_t *d ) { register char *end = d->end_text; register short token = 0; for (;;) { d->start_text = end; switch ( *end++ ) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: break; case 9: goto white_space ; break; case 10: ++d->line_number; goto white_space ; break; case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: break; case 32: white_space : while ( isspace ( *end ) ) { if ( *end == '\n' ) { ++d->line_number; } ++end; } break; case '!': if ( *end == '=' ) { ++end; token = ( NOT_EQUAL_ ); } else { token = ( '!' ); } break; case '\"': while ( *end ) { if ( *end == '\"' ) { ++end; while ( isspace ( *end ) ) { if ( *end == '\n' ) { ++d->line_number; } ++end; } if ( *end != '\"' ) { // string concatonation break; } } if ( *end == '\\' ) { ++end; } ++end; } token = ( STRING_ ); break; case '#': // skip # line while ( *end ) { if ( *end == '\n' ) { ++d->line_number; ++end; break; } ++end; } break; case 36: // invalid_char break; case '%': if ( *end == '=' ) { ++end; token = ( PERCENT_EQUAL_ ); } else { token = ( '%' ); } break; case '&': if ( *end == '&' ) { ++end; token = ( AND_AND_ ); } else if ( *end == '=' ) { ++end; token = ( AND_EQUAL_ ); } else { token = ( '&' ); } break; case '\'': while ( *end ) { if ( *end == '\'' ) { if ( *(end-1) == '\\' && *(end-2) != '\\' ){ // do nothing, continue the loop, found \' } else { ++end; break; } } ++end; } token = ( CHARACTER_CONSTANT_ ); break; case 40: case 41: // valid_token_char token = *(end - 1); break; case '*': if ( *end == '=' ) { ++end; token = ( STAR_EQUAL_ ); } else { token = ( '*' ); } break; case '+': if ( *end == '+' ) { ++end; token = ( PLUS_PLUS_ ); } else if ( *end == '=' ) { ++end; token = ( PLUS_EQUAL_ ); } else { token = ( '+' ); } break; case 44: token = *(end - 1); break; case '-': if ( *end == '-' ) { ++end; token = ( MINUS_MINUS_ ); } else if ( *end == '>' ) { ++end; token = ( MINUS_GREATER_ ); } else if ( *end == '=' ) { ++end; token = ( MINUS_EQUAL_ ); } else { token = ( '-' ); } break; case '.': if ( *end == '.' && *++end == '.' ) { ++end; token = ( DOT_DOT_DOT_ ); } else if ( isdigit ( *end ) ) { goto float_constant; } else { token = ( '.' ); } break; case '/': if ( *end == '=' ) { ++end; token = ( SLASH_EQUAL_ ); } else if ( *end == '/' ) { // comment while ( *++end ) { if ( *end == '\n' ) { ++end; if ( *end == '\r' ) { // for DOS ++end; } ++d->line_number; break; } } } else if ( *end == '*' ) { // comment while ( *++end ) { if ( *end == '\n' ) { ++d->line_number; continue; } if ( *end == '*' && *(end + 1) == '/' ) { end += 2; break; } } } else { token = ( '/' ); } break; case 48: // digit case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: while ( isdigit (*end) ) { ++end; } if ( ! (*end == '.' || *end == 'e' || *end == 'E') ) { if ( *end == 'x' || *end == 'X' ) { // int constant ++end; } while ( isxdigit (*end) ) { ++end; } if ( *end == 'u' || *end == 'U' || *end == 'l' || *end == 'L' ) { ++end; } if ( *end == 'u' || *end == 'U' || *end == 'l' || *end == 'L' ) { ++end; } token = ( INTEGER_CONSTANT_ ); break; } if ( *end == '.' ) { float_constant : while ( isdigit (*++end) ) { } } if ( *end == 'e' || *end == 'E' ) { ++end; } if ( *end == '-' || *end == '+' ) { ++end; } while ( isdigit (*end) ) { ++end; } if ( *end == 'f' || *end == 'F' || *end == 'l' || *end == 'L' ) { ++end; } token = ( FLOATING_CONSTANT_ ); break; case 58: case 59: token = *(end - 1); break; case '<': if ( *end == '=' ) { ++end; token = ( LESS_EQUAL_ ); } else if ( *end == '<' ) { if ( *++end == '=' ) { ++end; token = ( LESS_LESS_EQUAL_ ); } else { token = ( LESS_LESS_ ); } } else { token = ( '<' ); } break; case '=': if ( *end == '=' ) { ++end; token = ( EQUAL_EQUAL_ ); } else { token = ( '=' ); } break; case '>': if ( *end == '=' ) { ++end; token = ( GREATER_EQUAL_ ); } else if ( *end == '>' ) { if ( *++end == '=' ) { ++end; token = ( GREATER_GREATER_EQUAL_ ); } else { token = ( GREATER_GREATER_ ); } } else { token = ( '>' ); } break; case 63: token = *(end - 1); break; case 64: break; case 65: // upper alpha case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: goto identifier ; break; case 91: token = *(end - 1); break; case 92: break; case 93: token = *(end - 1); break; case '^': if ( *end == '=' ) { ++end; token = ( CARET_EQUAL_ ); } else { token = ( '^' ); } break; case 95: goto identifier ; break; case 96: break; case 97: // lower alpha case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: identifier : while ( *end ) { if ( ! ( isalnum ( *end ) || *end == '_' ) ) { token = IDENTIFIER_; break; } ++end; } break; case 123: token = *(end - 1); break; break; case '|': if ( *end == '|' ) { ++end; token = ( OR_OR_ ); } else if ( *end == '=' ) { ++end; token = ( OR_EQUAL_ ); } else { token = ( '|' ); } break; case 125: case 126: token = *(end - 1); break; case 127: break; } if ( ! *end ) { // check for end of buffer if ( d->end_of_input ) { if ( ! token ) { token = END_OF_SLK_INPUT_; --end; } } d->end_of_input = TRUE; } if ( token ) { token = install_name ( d, d->start_text, end, token ); d->end_text = end; return ( token ); } } } // ------------------------------------------------------------------------ // InitializeScanner // ------------------------------------------------------------------------ PUBLIC void InitializeScanner ( scanner_t *scanner, int trace, symbols_t *symbols, log_t *log, list_t *list ) { char *input = get_input_text ( log ); scanner->start_text = input; scanner->end_text = input; scanner->line_number = 1; scanner->end_of_input = FALSE; scanner->trace = trace; scanner->sym = symbols; scanner->log = log; scanner->list = list; scanner->get = get; } /************************************************************************* scanner.h Version 7.30 This module contains the public declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #ifndef _SCANNER_H #define _SCANNER_H #include "list.h" #include "symbol.h" // ------------------------------------------------------------------------ // scanner_t // // A pseudo-class to avoid global function names and enable initialization. // reentrant. // ------------------------------------------------------------------------ #undef SELF #define SELF struct _scanner typedef struct _scanner { log_t *log; symbols_t *sym; list_t *list; int line_number, end_of_input; int trace; char *start_text, *end_text; short (*get) ( SELF *id ); } scanner_t; #define get_line_number(self) (*self).line_number #define get(self) (*self).get(self) PUBLIC void InitializeScanner ( scanner_t *scanner, int trace, symbols_t *symbols, log_t *log, list_t *list ); #endif /************************************************************************* symbol.c Version 7.41 This module contains the symbol table manager. Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #include #include #include #include "symbol.h" #include "SlkTerminals.h" // ----------------------------------------------------------------------- // hash // // 32 bit hashing function for the hashtable // ----------------------------------------------------------------------- typedef unsigned int uint; PRIVATE uint hash ( char *string, uint table_size ) { register char *p = string - 1; register uint h = 0; register uint g; while ( *++p ) { h = (h << 4) + *p; g = (h & 0xF0000000); if ( g ) { h ^= (g >> 8); h ^= g; } } return ( h % table_size ); } // ----------------------------------------------------------------------- // lookup // // look up symbol in symbol table // ----------------------------------------------------------------------- INSTANCE_METHOD symbol_t * (lookup) ( symbols_t *d, register char *name ) { register symbol_t *symbol; short token; char message [ 128 ]; symbol = d->table [ hash ( name, d->table_size ) ]; for (; symbol; symbol = symbol->next ) { if ( ! ( symbol->deleted && (symbol->scope != d->table_scope) ) ) { if ( ! ( strcmp ( name, symbol->name ) ) ) { symbol->deleted = FALSE; d->current = symbol; token = symbol->token; if ( token == IDENTIFIER_ || token == TYPEDEF_NAME_ ) { d->last_identifier = symbol; } if ( d->trace ) { sprintf ( message, " old symbol[%u]: %s (%d) \n", symbol->scope, symbol->name, symbol->token ); trace ( d->log, message ); } break; // found it } } } return symbol; } // ----------------------------------------------------------------------- // insert // // insert a symbol into d->table // ----------------------------------------------------------------------- INSTANCE_METHOD symbol_t * (insert) ( symbols_t *d, short token, char *name ) { register symbol_t *new, *head; int hash_value; char message [ 128 ]; new = (symbol_t *) allocate ( &d->mem, sizeof (symbol_t) ); new->token = token; new->name = save ( &d->mem, name, strlen(name) + 1 ); new->scope = d->table_scope; d->current = new; if ( token == IDENTIFIER_ || token == TYPEDEF_NAME_ ) { d->last_identifier = new; } hash_value = hash ( name, d->table_size ); head = d->table [ hash_value ]; new->next = head; // insert at head of list d->table [ hash_value ] = new; if ( d->trace ) { sprintf ( message, " new symbol[%u]: %s (%d) \n", d->table_scope, name, token ); trace ( d->log, message ); } return ( new ); } // ----------------------------------------------------------------------- // release_table_scope // // remove all out of scope symbols from the symbol table by marking // them deleted. // --scope // ----------------------------------------------------------------------- INSTANCE_METHOD void (release_table_scope) ( symbols_t *d ) { register symbol_t **head = d->table, *symbol; int hash_value; for ( hash_value = 0; hash_value < d->table_size; ++hash_value ) { for ( symbol = *head++; symbol; symbol = symbol->next ) { if ( symbol->scope == d->table_scope ) { symbol->deleted = TRUE; } } } --d->table_scope; } // ----------------------------------------------------------------------- // print_table // // print out symbol table // ----------------------------------------------------------------------- INSTANCE_METHOD void (print_table) ( symbols_t *d ) { register symbol_t **head = d->table, *symbol; int hash_value; int total_symbols = 0, total_lists = 0, min_list_length = 10000, max_list_length = 0, avg_list_length = 0; char message [ 128 ]; sprintf ( message, "\n HASH SCOPE TOKEN NAME" "\n ------ ------- ------- ----------------\n" ); trace ( d->log, message ); for ( hash_value = 0; hash_value < d->table_size; ++hash_value ) { symbol = *head++; if ( symbol ) { int list_length = 0; for (; symbol; symbol = symbol->next ) { if ( symbol->deleted ) { sprintf ( message, "%6d (%2d) %6d %s \n", hash_value, symbol->scope, symbol->token, symbol->name); } else { sprintf ( message, "%6d %6d %6d %s \n", hash_value, symbol->scope, symbol->token, symbol->name); } trace ( d->log, message ); ++total_symbols; ++list_length; } if ( list_length < min_list_length ) { min_list_length = list_length; } if ( list_length > max_list_length ) { max_list_length = list_length; } avg_list_length += list_length; ++total_lists; } } avg_list_length /= total_lists; putchar ( '\n' ); sprintf ( message," total symbols = %6u \n", total_symbols ); trace ( d->log, message ); sprintf ( message," total lists = %6u \n", total_lists ); trace ( d->log, message ); sprintf ( message," min list length = %6u \n", min_list_length ); trace ( d->log, message ); sprintf ( message," max list length = %6u \n", max_list_length ); trace ( d->log, message ); sprintf ( message," avg list length = %6u \n", avg_list_length ); trace ( d->log, message ); } // ----------------------------------------------------------------------- // init_symbol_table with the terminals of the language // ----------------------------------------------------------------------- PRIVATE void init_symbol_table ( symbols_t *d ) { register Slk_terminal_t *terminal; for ( terminal = Slk_terminal; terminal->name; ++terminal ) { insert ( d, terminal->token, terminal->name ); } } // ----------------------------------------------------------------------- // release // ----------------------------------------------------------------------- INSTANCE_METHOD void (release) ( symbols_t *d ) { free ( d->table ); release ( &d->mem ); } // ----------------------------------------------------------------------- // InitializeSymbols // ----------------------------------------------------------------------- PUBLIC void InitializeSymbols ( register symbols_t *symbols, int trace, int table_size, log_t *log ) { symbols->trace = trace; symbols->table_size = table_size; symbols->log = log; symbols->table_scope = 1; symbols->current = NULL; symbols->last_identifier = NULL; symbols->table = (symbol_t **) calloc ( table_size+2, sizeof (symbol_t *)); InitializeMemory ( &symbols->mem ); symbols->lookup = lookup; symbols->insert = insert; symbols->print_table = print_table; symbols->release_table_scope = release_table_scope; symbols->release = release; init_symbol_table ( symbols ); } /************************************************************************* symbol.h Version 7.30 This module contains the public symbol_node declarations. Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #ifndef _SYMBOL_H #define _SYMBOL_H #include "memory.h" #include "log.h" // #define HASHSIZE 1013 // prime number: 211 503 1013 10007 40013 // ----------------------------------------------------------------------- // symbol_t // // symbol table entry node // ----------------------------------------------------------------------- typedef struct _symbol { struct _symbol *next; char *name; short token; char scope; char deleted; } symbol_t; // ------------------------------------------------------------------------ // symbols_t // // A pseudo-class to avoid global function names and enable initialization. // reentrant. // ------------------------------------------------------------------------ #undef SELF #define SELF struct _symbols typedef struct _symbols { symbol_t **table; // array of head nodes symbol_t *current; // current symbol table entry symbol_t *last_identifier; // for typedef memory_t mem; log_t *log; int table_size, trace; char table_scope; symbol_t *(*lookup) ( SELF *id, char *name ); symbol_t *(*insert) ( SELF *id, short token, char *name ); void (*print_table) ( SELF *id ); void (*release_table_scope) ( SELF *id ); void (*release) ( SELF *id ); } symbols_t; #define get_current(self) (*self).current #define set_current(self,a) ((*self).current = a) #define get_last_identifier(self) (*self).last_identifier #define set_new_table_scope(self) ++(*self).table_scope #define get_table_scope(self) (*self).table_scope #define lookup(self,a) (*self).lookup(self, a) #define insert(self,a,b) (*self).insert(self, a, b) #define print_table(self) (*self).print_table(self) #define release_table_scope(self) (*self).release_table_scope(self) #define release(self) (*self).release(self) PUBLIC void InitializeSymbols ( symbols_t *symbols, int trace, int table_size, log_t *log ); #endif /****************************************************************************** tree.c Version 7.40 This module contains the parse tree code. Copyright (c) 2002-2012 SLK Systems, all rights reserved. ******************************************************************************/ #include #include "tree.h" #include "SlkParse.h" #include "SlkString.h" #undef push #undef pop #define push(n,s) if (s.top > s.start) { *--s.top = n; }\ else { puts ("tree_t: stack overflow"); exit(1); } #define pop(s) ( *s.top ? *s.top++ : 0 ) #define init_node(node,token) { *node = zeroed_node; node->token = token; } PRIVATE node_t zeroed_node; // should be zeroes PRIVATE int released_nodes; // statistics PRIVATE int reused_nodes; // ======================================================================= // local usage only - node // ======================================================================= #ifdef UNIT_TEST PRIVATE void show_free_nodes ( tree_t *d ) { register node_t *node = d->free_nodes; for (; node; node = node->next ) { printf ( "%s\n", SlkGetSymbolName ( node->token ) ); } } #endif PRIVATE void release_node ( tree_t *d, node_t *node ) { if ( d->free_nodes ) { node->next = d->free_nodes; // put at head of list ++released_nodes; } d->free_nodes = node; } PRIVATE node_t * new_node ( tree_t *d, short token ) { node_t *node; if ( d->free_nodes ) { node = d->free_nodes; d->free_nodes = d->free_nodes->next; node->next = NULL; ++reused_nodes; } else { node = (node_t *) allocate ( &d->mem, sizeof (node_t) ); } init_node ( node, token ); return node; } #ifdef UNIT_TEST PRIVATE void print_production ( register node_t *rhs ) { if ( ! rhs ) { return; } while ( rhs->left_sibling ) { rhs = rhs->left_sibling; } printf ( "%s --> %s ", SlkGetSymbolName ( rhs->parent->token ) , SlkGetSymbolName ( rhs->token ) ); while ( rhs->sibling ) { printf ( "%s ", SlkGetSymbolName ( rhs->sibling->token ) ); rhs = rhs->sibling; } putchar ( '\n' ); } #endif PRIVATE void delete_node ( tree_t *d, register node_t *node ) { register node_t *left_sibling; // left side sibling back pointer node_t *parent; // lhs of production // print_production ( node ); // printf ( "CURRENT: %s\n", SlkGetSymbolName ( node->token ) ); left_sibling = node->left_sibling; if ( left_sibling ) { // printf ( " LEFT SIBLING: %s\n", SlkGetSymbolName ( left_sibling->token ) ); left_sibling->sibling = node->sibling; if ( node->sibling ) { node->sibling->left_sibling = left_sibling; } release_node ( d, node ); // print_production ( left_sibling ); } else { parent = node->parent; if ( parent ) { // printf ( " PARENT: %s\n", SlkGetSymbolName ( parent->token ) ); parent->child = node->sibling; // printf ( " CHILD: %s\n", SlkGetSymbolName ( parent->child->token )); if ( node->sibling ) { node->sibling->parent = parent; node->sibling->left_sibling = NULL; } release_node ( d, node ); // print_production ( parent->child ); } else { puts ( "tree_t: no parent or left sibling" ); } } } PRIVATE void lift_child ( tree_t *d, register node_t *parent ) // to lift up a child node to parent { // just rewrite the parent node register // then delete the child node_t *child = parent->child; if ( ! child ) { return; } // print_production ( parent ); parent->symbol = child->symbol; parent->token = child->token; if ( child->sibling ) { parent->child = child->sibling; child->sibling->parent = parent; child->sibling->left_sibling = NULL; } else if ( child->child ) { parent->child = child->child; child->child->parent = parent; } else { parent->child = NULL; } release_node ( d, child ); // print_production ( parent ); putchar ( '\n' ); } // ======================================================================= // local usage only - tree recursives // ======================================================================= PRIVATE void in_order ( node_t *tree ) { register node_t *child, *sibling; if ( ! tree ) { return; } child = tree->child; if ( child ) { in_order ( child ); } if ( SlkIsTerminal ( tree->token ) ) { char *spaces = " "; switch ( tree->token ) { // pretty print it case LBRACE_: case RBRACE_: case SEMI_: spaces = "\n"; break; case DOT_: case COMMA_: spaces = ""; break; } printf ( "%s%s", tree->symbol->name, spaces ); /********** debug if ( tree->symbol->token != tree->token ) { printf ( "\n tree->token: %s\n", SlkGetSymbolName ( tree->token )); printf ( " tree->symbol->token: %s\n", SlkGetSymbolName ( tree->symbol->token ) ); } *************/ } if ( child ) { for ( sibling = child->sibling; sibling; sibling = sibling->sibling ){ in_order ( sibling ); } } } PRIVATE void show_parse_derivation_r ( node_t *tree ) { register node_t *child, *sibling; if ( ! tree ) { return; } /******* debug if ( tree->parent ) { printf ( "%s parent is %s\n", tree->symbol->name, tree->parent->symbol->name ); } ********/ printf ( "%s --> ", SlkGetSymbolName ( tree->token ) ); child = tree->child; if ( child ) { printf ( "%s ", SlkGetSymbolName ( child->token ) ); for ( sibling = child->sibling; sibling; sibling = sibling->sibling ) { printf ( "%s ", SlkGetSymbolName ( sibling->token ) ); } putchar ( '\n' ); if ( SlkIsNonterminal ( child->token ) ) { show_parse_derivation_r ( child ); } for ( sibling = child->sibling; sibling; sibling = sibling->sibling ) { if ( SlkIsNonterminal ( sibling->token ) ) { show_parse_derivation_r ( sibling ); } } } else { putchar ( '\n' ); } } PRIVATE void lift_single_rhs_symbol ( tree_t *d, node_t *tree ) { register // remove chains of precedence productions node_t *child, *sibling; if ( ! tree ) { return; } // printf ( "tree: %s\n", tree->symbol->name ); child = tree->child; if ( child ) { lift_single_rhs_symbol ( d, child ); if ( ! child->sibling ) { if ( tree != d->root ) { lift_child ( d, tree ); // lift up child } } for ( sibling = child->sibling; sibling; sibling = sibling->sibling ){ lift_single_rhs_symbol ( d, sibling ); } } } // ----------------------------------------------------------------------- // add_symbols_r - put the symbols on the tree // // problem with stacking because cannot get at symbol at the right time // so just save the symbols linearly while scanning, // then decorate the tree with them here, in order // ----------------------------------------------------------------------- PRIVATE void add_symbols_r ( tree_t *d, node_t *tree ) { register node_t *child, *sibling; if ( ! tree ) { return; } child = tree->child; if ( child ) { add_symbols_r ( d, child ); } if ( SlkIsTerminal ( tree->token ) && ! tree->symbol ) { tree->symbol = get_next(d->list); if ( tree->symbol ) { // printf ( "\n symbol token: %s \n", tree->symbol->name ); // printf ( " tree token: %s \n", SlkGetSymbolName ( tree->token )); } else { printf ( "no symbol for '%s'\n", SlkGetSymbolName ( tree->token ) ); } } if ( child ) { for ( sibling = child->sibling; sibling; sibling = sibling->sibling ){ add_symbols_r ( d, sibling ); } } } // ======================================================================= // INSTANCE_METHOD - public usage through a struct // ======================================================================= // ================ these are for SLK ======================= INSTANCE_METHOD void (make_root) ( tree_t *d, short token ) { d->root = new_node ( d, token ); d->current = d->root; // did not pop the root } INSTANCE_METHOD void (push_rhs_symbol) ( tree_t *d, short token ) { node_t *node = new_node ( d, token ); push ( node, d->parse_stack ); push ( node, d->rhs_stack ); } INSTANCE_METHOD void (pop_current) ( tree_t *d ) // happens just after add_rhs { // so previous current is lhs d->current = pop ( d->parse_stack ); } INSTANCE_METHOD void (add_rhs) ( tree_t *d ) { // current == lhs register node_t *node, *rhs; node_t *lhs = d->current; node = pop ( d->rhs_stack ); while ( node && SlkIsAction ( node->token ) ) { node = pop ( d->rhs_stack ); // delete action nodes } if ( ! node ) { delete_node ( d, lhs ); // remove null production } if ( node ) { lhs->child = node; rhs = node; rhs->parent = lhs; // print_production ( node ); node = pop ( d->rhs_stack ); /**** try to make this work ? if ( ! node ) { if ( lhs != d->root ) { lift_child ( d, lhs ); // lift single rhs symbol } } ****/ while ( node ) { if ( SlkIsAction ( node->token ) ) { node = pop ( d->rhs_stack ); // delete action node continue; } node->left_sibling = rhs; rhs->sibling = node; rhs = node; node = pop ( d->rhs_stack ); } } } // ================ user level methods ======================= INSTANCE_METHOD void (show_tree) ( tree_t *d ) { in_order ( d->root ); } INSTANCE_METHOD void (show_parse_derivation) ( tree_t *d ) { show_parse_derivation_r ( d->root ); } INSTANCE_METHOD void (prune) ( tree_t *d ) { lift_single_rhs_symbol ( d, d->root ); // show_free_nodes ( d ); // show_all ( d->list ); } // ----------------------------------------------------------------------- // add_symbols - put the symbols on the tree // // problem with stacking because cannot get at symbol at the right time // so just save the symbols linearly while scanning, // then decorate the tree with them here, in order // ----------------------------------------------------------------------- INSTANCE_METHOD void (add_symbols) ( tree_t *d ) { add_symbols_r ( d, d->root ); // printf ( "\nreleased nodes = %d\n", released_nodes ); // printf ( "reused nodes = %d\n", reused_nodes ); // printf ( "reused memory = %d\n\n", reused_nodes * (sizeof (node_t))); } INSTANCE_METHOD void (release) ( tree_t *d ) { release ( &d->mem ); } // ======================================================================= // InitializeTree - public to set the tree values to the initial state // ======================================================================= PUBLIC void InitializeTree ( tree_t *tree, int trace, log_t *log, symbols_t *sym, list_t *list ) { tree->log = log; tree->sym = sym; tree->list = list; tree->trace = trace; tree->root = NULL; tree->current = NULL; tree->free_nodes = NULL; tree->parse_stack.top = tree->parse_stack.start + STACKSIZE - 1; *tree->parse_stack.top = NULL; tree->rhs_stack.top = tree->rhs_stack.start + STACKSIZE - 1; *tree->rhs_stack.top = NULL; InitializeMemory ( &tree->mem ); tree->make_root = make_root; tree->push_rhs_symbol = push_rhs_symbol; tree->add_rhs = add_rhs; tree->pop_current = pop_current; tree->show_tree = show_tree; tree->show_parse_derivation = show_parse_derivation; tree->prune = prune; tree->add_symbols = add_symbols; tree->release = release; } /************************************************************************* tree.h Version 7.38 This module contains the parse tree declarations Copyright (c) 2002-2012 SLK Systems, all rights reserved. *************************************************************************/ #ifndef _SLKTREE_C_H #define _SLKTREE_C_H #include "log.h" #include "list.h" #include "symbol.h" #define PRIVATE static #define PUBLIC #define INSTANCE_METHOD static typedef struct _node { struct _node *next, // list of free nodes for reuse *parent, // parent is the lhs of the child production *child, // first symbol on rhs of production *sibling, // rest of the parent production is siblings *left_sibling; // left side sibling back pointer symbol_t *symbol; // symbol table entry short token; } node_t; #define STACKSIZE 512 typedef struct _stack { node_t **top , *start [ STACKSIZE ]; } stack_t; // ------------------------------------------------------------------------ // tree_t // // A struct to avoid public names, enable initialization, and // provide instance data so it is reentrant. // The struct only goes away when its declaration goes out of scope. // Any cleanup should be in release. // ------------------------------------------------------------------------ #undef SELF #define SELF struct _tree typedef struct _tree { log_t *log; symbols_t *sym; list_t *list; int trace; node_t *root; node_t *current; node_t *free_nodes; stack_t parse_stack; stack_t rhs_stack; memory_t mem; void (*make_root) ( SELF *id, short symbol ); void (*push_rhs_symbol) ( SELF *id, short symbol ); void (*add_rhs) ( SELF *id ); void (*pop_current) ( SELF *id ); void (*show_tree) ( SELF *id ); void (*show_parse_derivation) ( SELF *id ); void (*prune) ( SELF *id ); void (*add_symbols) ( SELF *id ); void (*release) ( SELF *id ); } tree_t, SlkTree; #define get_current(self) (*self).current #define set_current(self,a) ((*self).current = a) #define make_root(self,a) (*self).make_root(self,a) #define push_rhs_symbol(self,a) (*self).push_rhs_symbol(self,a) #define add_rhs(self) (*self).add_rhs(self) #define pop_current(self) (*self).pop_current(self) #define show_tree(self) (*self).show_tree(self) #define show_parse_derivation(self) (*self).show_parse_derivation(self) #define prune(self) (*self).prune(self) #define add_symbols(self) (*self).add_symbols(self) #define release(self) (*self).release(self) PUBLIC void InitializeTree ( tree_t *tree, int trace, log_t *log, symbols_t *sym, list_t *list ); #endif