diff options
Diffstat (limited to 'tools/build/src/engine/function.c')
-rw-r--r-- | tools/build/src/engine/function.c | 200 |
1 files changed, 175 insertions, 25 deletions
diff --git a/tools/build/src/engine/function.c b/tools/build/src/engine/function.c index d9ad754e43..9cb1718867 100644 --- a/tools/build/src/engine/function.c +++ b/tools/build/src/engine/function.c @@ -19,6 +19,7 @@ #include "rules.h" #include "search.h" #include "variable.h" +#include "output.h" #include <assert.h> #include <stdio.h> @@ -119,6 +120,8 @@ void backtrace_line( FRAME * ); #define INSTR_WRITE_FILE 54 #define INSTR_OUTPUT_STRINGS 55 +#define INSTR_FOR_POP 70 + typedef struct instruction { unsigned int op_code; @@ -449,7 +452,7 @@ static LIST * function_call_rule( JAM_FUNCTION * function, FRAME * frame, if ( list_empty( first ) ) { backtrace_line( frame ); - printf( "warning: rulename %s expands to empty string\n", unexpanded ); + out_printf( "warning: rulename %s expands to empty string\n", unexpanded ); backtrace( frame ); list_free( first ); for ( i = 0; i < n_args; ++i ) @@ -505,7 +508,7 @@ static LIST * function_call_member_rule( JAM_FUNCTION * function, FRAME * frame, if ( list_empty( first ) ) { backtrace_line( frame ); - printf( "warning: object is empty\n" ); + out_printf( "warning: object is empty\n" ); backtrace( frame ); list_free( first ); @@ -1313,7 +1316,7 @@ static void dynamic_array_push_impl( struct dynamic_array * const array, #define dynamic_array_push( array, value ) (dynamic_array_push_impl(array, &value, sizeof(value))) #define dynamic_array_at( type, array, idx ) (((type *)(array)->data)[idx]) - +#define dynamic_array_pop( array ) (--(array)->size) /* * struct compiler @@ -1325,6 +1328,16 @@ struct label_info struct dynamic_array uses[ 1 ]; }; +#define LOOP_INFO_BREAK 0 +#define LOOP_INFO_CONTINUE 1 + +struct loop_info +{ + int type; + int label; + int cleanup_depth; +}; + struct stored_rule { OBJECT * name; @@ -1341,6 +1354,8 @@ typedef struct compiler struct dynamic_array labels[ 1 ]; struct dynamic_array rules[ 1 ]; struct dynamic_array actions[ 1 ]; + struct dynamic_array cleanups[ 1 ]; + struct dynamic_array loop_scopes[ 1 ]; } compiler; static void compiler_init( compiler * c ) @@ -1350,6 +1365,8 @@ static void compiler_init( compiler * c ) dynamic_array_init( c->labels ); dynamic_array_init( c->rules ); dynamic_array_init( c->actions ); + dynamic_array_init( c->cleanups ); + dynamic_array_init( c->loop_scopes ); } static void compiler_free( compiler * c ) @@ -1363,6 +1380,8 @@ static void compiler_free( compiler * c ) dynamic_array_free( c->labels ); dynamic_array_free( c->constants ); dynamic_array_free( c->code ); + dynamic_array_free( c->cleanups ); + dynamic_array_free( c->loop_scopes ); } static void compile_emit_instruction( compiler * c, instruction instr ) @@ -1428,6 +1447,82 @@ static int compile_emit_constant( compiler * c, OBJECT * value ) return c->constants->size - 1; } +static void compile_push_cleanup( compiler * c, unsigned int op_code, int arg ) +{ + instruction instr; + instr.op_code = op_code; + instr.arg = arg; + dynamic_array_push( c->cleanups, instr ); +} + +static void compile_pop_cleanup( compiler * c ) +{ + dynamic_array_pop( c->cleanups ); +} + +static void compile_emit_cleanups( compiler * c, int end ) +{ + int i; + for ( i = c->cleanups->size; --i >= end; ) + { + compile_emit_instruction( c, dynamic_array_at( instruction, c->cleanups, i ) ); + } +} + +static void compile_emit_loop_jump( compiler * c, int type ) +{ + struct loop_info * info = NULL; + int i; + for ( i = c->loop_scopes->size; --i >= 0; ) + { + struct loop_info * elem = &dynamic_array_at( struct loop_info, c->loop_scopes, i ); + if ( elem->type == type ) + { + info = elem; + break; + } + } + if ( info == NULL ) + { + printf( "warning: ignoring break statement used outside of loop\n" ); + return; + } + compile_emit_cleanups( c, info->cleanup_depth ); + compile_emit_branch( c, INSTR_JUMP, info->label ); +} + +static void compile_push_break_scope( compiler * c, int label ) +{ + struct loop_info info; + info.type = LOOP_INFO_BREAK; + info.label = label; + info.cleanup_depth = c->cleanups->size; + dynamic_array_push( c->loop_scopes, info ); +} + +static void compile_push_continue_scope( compiler * c, int label ) +{ + struct loop_info info; + info.type = LOOP_INFO_CONTINUE; + info.label = label; + info.cleanup_depth = c->cleanups->size; + dynamic_array_push( c->loop_scopes, info ); +} + +static void compile_pop_break_scope( compiler * c ) +{ + assert( c->loop_scopes->size > 0 ); + assert( dynamic_array_at( struct loop_info, c->loop_scopes, c->loop_scopes->size - 1 ).type == LOOP_INFO_BREAK ); + dynamic_array_pop( c->loop_scopes ); +} + +static void compile_pop_continue_scope( compiler * c ) +{ + assert( c->loop_scopes->size > 0 ); + assert( dynamic_array_at( struct loop_info, c->loop_scopes, c->loop_scopes->size - 1 ).type == LOOP_INFO_CONTINUE ); + dynamic_array_pop( c->loop_scopes ); +} + static int compile_emit_rule( compiler * c, OBJECT * name, PARSE * parse, int num_arguments, struct arg_list * arguments, int local ) { @@ -1991,7 +2086,7 @@ static int current_line; static void parse_error( char const * message ) { - printf( "%s:%d: %s\n", current_file, current_line, message ); + out_printf( "%s:%d: %s\n", current_file, current_line, message ); } @@ -2397,7 +2492,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) int f = compile_new_label( c ); int end = compile_new_label( c ); - printf( "%s:%d: Conditional used as list (check operator " + out_printf( "%s:%d: Conditional used as list (check operator " "precedence).\n", object_str( parse->file ), parse->line ); /* Emit the condition */ @@ -2416,6 +2511,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) int var = compile_emit_constant( c, parse->string ); int top = compile_new_label( c ); int end = compile_new_label( c ); + int continue_ = compile_new_label( c ); /* * Evaluate the list. @@ -2428,6 +2524,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) compile_emit( c, INSTR_PUSH_EMPTY, 0 ); compile_emit( c, INSTR_PUSH_LOCAL, var ); compile_emit( c, INSTR_SWAP, 1 ); + compile_push_cleanup( c, INSTR_POP_LOCAL, var ); } compile_emit( c, INSTR_FOR_INIT, 0 ); @@ -2435,14 +2532,26 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) compile_emit_branch( c, INSTR_FOR_LOOP, end ); compile_emit( c, INSTR_SET, var ); + compile_push_break_scope( c, end ); + compile_push_cleanup( c, INSTR_FOR_POP, 0 ); + compile_push_continue_scope( c, continue_ ); + /* Run the loop body */ compile_parse( parse->right, c, RESULT_NONE ); + compile_pop_continue_scope( c ); + compile_pop_cleanup( c ); + compile_pop_break_scope( c ); + + compile_set_label( c, continue_ ); compile_emit_branch( c, INSTR_JUMP, top ); compile_set_label( c, end ); if ( parse->num ) + { + compile_pop_cleanup( c ); compile_emit( c, INSTR_POP_LOCAL, var ); + } adjust_result( c, RESULT_NONE, result_location); } @@ -2473,6 +2582,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) : RESULT_RETURN; int test = compile_new_label( c ); int top = compile_new_label( c ); + int end = compile_new_label( c ); /* Make sure that we return an empty list if the loop runs zero times. */ adjust_result( c, RESULT_NONE, nested_result ); @@ -2480,10 +2590,15 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) compile_emit_branch( c, INSTR_JUMP, test ); compile_set_label( c, top ); /* Emit the loop body. */ + compile_push_break_scope( c, end ); + compile_push_continue_scope( c, test ); compile_parse( parse->right, c, nested_result ); + compile_pop_continue_scope( c ); + compile_pop_break_scope( c ); /* Emit the condition. */ compile_set_label( c, test ); compile_condition( parse->left, c, 1, top ); + compile_set_label( c, end ); adjust_result( c, nested_result, result_location ); } @@ -2501,7 +2616,9 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) : RESULT_RETURN; compile_parse( parse->left, c, RESULT_STACK ); compile_emit( c, INSTR_PUSH_MODULE, 0 ); + compile_push_cleanup( c, INSTR_POP_MODULE, 0 ); compile_parse( parse->right, c, nested_result ); + compile_pop_cleanup( c ); compile_emit( c, INSTR_POP_MODULE, 0 ); adjust_result( c, nested_result, result_location ); } @@ -2515,8 +2632,10 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) else compile_emit( c, INSTR_PUSH_EMPTY, 0 ); compile_emit( c, INSTR_CLASS, 0 ); + compile_push_cleanup( c, INSTR_POP_MODULE, 0 ); compile_parse( parse->right, c, RESULT_NONE ); compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 ); + compile_pop_cleanup( c ); compile_emit( c, INSTR_POP_MODULE, 0 ); adjust_result( c, RESULT_NONE, result_location ); @@ -2566,7 +2685,9 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) var_parse_group_free( group ); compile_parse( parse->right, c, RESULT_STACK ); compile_emit( c, INSTR_PUSH_LOCAL, name ); + compile_push_cleanup( c, INSTR_POP_LOCAL, name ); compile_parse( parse->third, c, nested_result ); + compile_pop_cleanup( c ); compile_emit( c, INSTR_POP_LOCAL, name ); } else @@ -2575,7 +2696,9 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) var_parse_group_free( group ); compile_parse( parse->right, c, RESULT_STACK ); compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 ); + compile_push_cleanup( c, INSTR_POP_LOCAL_GROUP, 0 ); compile_parse( parse->third, c, nested_result ); + compile_pop_cleanup( c ); compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 ); } } @@ -2584,7 +2707,9 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) compile_parse( parse->left, c, RESULT_STACK ); compile_parse( parse->right, c, RESULT_STACK ); compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 ); + compile_push_cleanup( c, INSTR_POP_LOCAL_GROUP, 0 ); compile_parse( parse->third, c, nested_result ); + compile_pop_cleanup( c ); compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 ); } adjust_result( c, nested_result, result_location ); @@ -2632,7 +2757,9 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) int end = compile_new_label( c ); compile_parse( parse->left, c, RESULT_STACK ); compile_emit_branch( c, INSTR_PUSH_ON, end ); + compile_push_cleanup( c, INSTR_POP_ON, 0 ); var_parse_group_compile( group, c ); + compile_pop_cleanup( c ); compile_emit( c, INSTR_POP_ON, 0 ); compile_set_label( c, end ); } @@ -2643,7 +2770,9 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) int end = compile_new_label( c ); compile_parse( parse->left, c, RESULT_STACK ); compile_emit_branch( c, INSTR_PUSH_ON, end ); + compile_push_cleanup( c, INSTR_POP_ON, 0 ); compile_parse( parse->right, c, RESULT_STACK ); + compile_pop_cleanup( c ); compile_emit( c, INSTR_POP_ON, 0 ); compile_set_label( c, end ); } @@ -2809,6 +2938,20 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) adjust_result( c, RESULT_NONE, result_location ); compile_set_label( c, switch_end ); } + else if ( parse->type == PARSE_RETURN ) + { + compile_parse( parse->left, c, RESULT_RETURN ); + compile_emit_cleanups( c, 0 ); + compile_emit( c, INSTR_RETURN, 0 ); + } + else if ( parse->type == PARSE_BREAK ) + { + compile_emit_loop_jump( c, LOOP_INFO_BREAK ); + } + else if ( parse->type == PARSE_CONTINUE ) + { + compile_emit_loop_jump( c, LOOP_INFO_CONTINUE ); + } else if ( parse->type == PARSE_NULL ) adjust_result( c, RESULT_NONE, result_location ); else @@ -2925,15 +3068,15 @@ static void argument_error( char const * message, FUNCTION * procedure, extern void print_source_line( FRAME * ); LOL * actual = frame->args; backtrace_line( frame->prev ); - printf( "*** argument error\n* rule %s ( ", frame->rulename ); + out_printf( "*** argument error\n* rule %s ( ", frame->rulename ); argument_list_print( procedure->formal_arguments, procedure->num_formal_arguments ); - printf( " )\n* called with: ( " ); + out_printf( " )\n* called with: ( " ); lol_print( actual ); - printf( " )\n* %s %s\n", message, arg ? object_str ( arg ) : "" ); + out_printf( " )\n* %s %s\n", message, arg ? object_str ( arg ) : "" ); function_location( procedure, &frame->file, &frame->line ); print_source_line( frame ); - printf( "see definition of rule '%s' being called\n", frame->rulename ); + out_printf( "see definition of rule '%s' being called\n", frame->rulename ); backtrace( frame->prev ); exit( 1 ); } @@ -3226,7 +3369,7 @@ static void argument_compiler_add( struct argument_compiler * c, OBJECT * arg, if ( is_type_name( object_str( arg ) ) ) { - printf( "%s:%d: missing argument name before type name: %s\n", + err_printf( "%s:%d: missing argument name before type name: %s\n", object_str( file ), line, object_str( arg ) ); exit( 1 ); } @@ -3274,7 +3417,7 @@ static struct arg_list arg_compile_impl( struct argument_compiler * c, case ARGUMENT_COMPILER_DONE: break; case ARGUMENT_COMPILER_FOUND_TYPE: - printf( "%s:%d: missing argument name after type name: %s\n", + err_printf( "%s:%d: missing argument name after type name: %s\n", object_str( file ), line, object_str( c->arg.type_name ) ); exit( 1 ); case ARGUMENT_COMPILER_FOUND_OBJECT: @@ -3398,19 +3541,19 @@ static void argument_list_print( struct arg_list * args, int num_args ) for ( i = 0; i < num_args; ++i ) { int j; - if ( i ) printf( " : " ); + if ( i ) out_printf( " : " ); for ( j = 0; j < args[ i ].size; ++j ) { struct argument * formal_arg = &args[ i ].args[ j ]; - if ( j ) printf( " " ); + if ( j ) out_printf( " " ); if ( formal_arg->type_name ) - printf( "%s ", object_str( formal_arg->type_name ) ); - printf( "%s", object_str( formal_arg->arg_name ) ); + out_printf( "%s ", object_str( formal_arg->type_name ) ); + out_printf( "%s", object_str( formal_arg->arg_name ) ); switch ( formal_arg->flags ) { - case ARG_OPTIONAL: printf( " ?" ); break; - case ARG_PLUS: printf( " +" ); break; - case ARG_STAR: printf( " *" ); break; + case ARG_OPTIONAL: out_printf( " ?" ); break; + case ARG_PLUS: out_printf( " +" ); break; + case ARG_STAR: out_printf( " *" ); break; } } } @@ -3877,6 +4020,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) break; } + case INSTR_FOR_POP: + { + stack_deallocate( s, sizeof( LISTITER ) ); + list_free( stack_pop( s ) ); + break; + } + /* * Switch */ @@ -3925,7 +4075,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) frame->file = function->file; frame->line = function->line; backtrace_line( frame ); - printf( "error: stack check failed.\n" ); + out_printf( "error: stack check failed.\n" ); backtrace( frame ); assert( saved_stack == s->data ); } @@ -4566,16 +4716,16 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) if ( !out_file ) { - printf( "failed to write output file '%s'!\n", + err_printf( "failed to write output file '%s'!\n", out_name->value ); exit( EXITBAD ); } string_free( out_name ); } - if ( out_debug ) printf( "\nfile %s\n", out ); + if ( out_debug ) out_printf( "\nfile %s\n", out ); if ( out_file ) fputs( buf->value, out_file ); - if ( out_debug ) fputs( buf->value, stdout ); + if ( out_debug ) out_puts( buf->value ); if ( out_file ) { fflush( out_file ); @@ -4585,7 +4735,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) if ( tmp_filename ) object_free( tmp_filename ); - if ( out_debug ) fputc( '\n', stdout ); + if ( out_debug ) out_putc( '\n' ); break; } @@ -4833,7 +4983,7 @@ static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame ) { OBJECT * s = python_to_string( PyList_GetItem( py_result, i ) ); if ( !s ) - fprintf( stderr, + err_printf( "Non-string object returned by Python call.\n" ); else result = list_push_back( result, s ); @@ -4864,7 +5014,7 @@ static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame ) else { PyErr_Print(); - fprintf( stderr, "Call failed\n" ); + err_printf( "Call failed\n" ); } return result; |