summaryrefslogtreecommitdiff
path: root/tools/build/src/engine/function.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/build/src/engine/function.c')
-rw-r--r--tools/build/src/engine/function.c200
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;