summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2020-08-15 19:51:05 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2020-08-15 19:51:05 +0200
commitc096d1707246c8631219365034e11b28652c98f4 (patch)
treecf6d80111fcd91f3095cbc0b0c70c1d3fcb893c5
parent3d41b8813db0ebe45ce7d0c54604554812ddb484 (diff)
downloadcompilertests-c096d1707246c8631219365034e11b28652c98f4.tar.gz
compilertests-c096d1707246c8631219365034e11b28652c98f4.tar.bz2
correct returning from procedure with arguments
- ec: first working return from a procedure with parameters - asm-i386: needed a ret imm16 to clean up stack when returning from call with parameters - asm-i386: introduced min and max operands constraints (better than arbitrary expections by opcode, for instance dd)
-rw-r--r--ecomp-c/asm-i386.c113
-rw-r--r--ecomp-c/ec.c46
-rwxr-xr-xecomp-c/test.sh1
-rw-r--r--ecomp-c/tests/procedure_call.easm1
-rw-r--r--ecomp-c/tests/procedure_call_value_parameters.e6
-rw-r--r--ecomp-c/tests/procedure_forward_declaration.easm2
-rw-r--r--ecomp-c/tests/procedure_local_variables.easm1
-rw-r--r--ecomp-c/tests/procedure_scoping.easm2
8 files changed, 120 insertions, 52 deletions
diff --git a/ecomp-c/asm-i386.c b/ecomp-c/asm-i386.c
index c9de15a..584c631 100644
--- a/ecomp-c/asm-i386.c
+++ b/ecomp-c/asm-i386.c
@@ -32,6 +32,7 @@
* E9 XX XX XX XX jmp rel32
* E8 XX XX XX XX call rel32
* C3 ret
+ * C2 XX XX ret imm16
* F4 hlt
* CD XX int nnn
* 90 nop
@@ -52,6 +53,9 @@
* rel32
* relative address offset (8/32 bits)
*
+ * imm16
+ * little endian 16-bit constant
+ *
* format binary
* use32
* org 0x00000000
@@ -68,7 +72,8 @@ enum {
MAX_NUMBER_LEN = 10,
MAX_HEXNUMBER_LEN = 8,
MAX_STRING_LEN = 64,
- MAX_PASSES = 10
+ MAX_PASSES = 10,
+ MAX_NOF_OPERANDS = 64
};
static int DEBUG_GETCHAR = 0;
@@ -842,7 +847,8 @@ typedef struct OpcodeInfo {
Symbol *label;
int addr;
Opcode opcode;
- int nof_operands;
+ int min_operands;
+ int max_operands;
OperandInfo *operand;
struct OpcodeInfo *next;
int size;
@@ -866,51 +872,60 @@ static OpcodeInfo *parseOpcode( void )
case 'a':
if( strcmp( ident, "add" ) == 0 ) {
opcode_info->opcode = OPCODE_ADD;
- opcode_info->nof_operands = 2;
+ opcode_info->min_operands = 2;
+ opcode_info->max_operands = 2;
opcode_info->size = 2;
}
break;
case 'c':
if( strcmp( ident, "cmp" ) == 0 ) {
opcode_info->opcode = OPCODE_CMP;
- opcode_info->nof_operands = 2;
+ opcode_info->min_operands = 2;
+ opcode_info->max_operands = 2;
opcode_info->size = 2;
} else if( strcmp( ident, "call" ) == 0 ) {
opcode_info->opcode = OPCODE_CALL;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 5;
}
break;
case 'd':
if( strcmp( ident, "dd" ) == 0 ) {
opcode_info->opcode = OPCODE_PSEUDO_DD;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = MAX_NOF_OPERANDS;
opcode_info->size = 4;
} else if( strcmp( ident, "db" ) == 0 ) {
opcode_info->opcode = OPCODE_PSEUDO_DB;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = MAX_NOF_OPERANDS;
opcode_info->size = 1;
} else if( strcmp( ident, "dw" ) == 0 ) {
opcode_info->opcode = OPCODE_PSEUDO_DW;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = MAX_NOF_OPERANDS;
opcode_info->size = 2;
} else if( strcmp( ident, "div" ) == 0 ) {
opcode_info->opcode = OPCODE_DIV;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
}
break;
case 'h':
if( strcmp( ident, "hlt" ) == 0 ) {
opcode_info->opcode = OPCODE_HLT;
- opcode_info->nof_operands = 0;
+ opcode_info->min_operands = 0;
+ opcode_info->max_operands = 0;
opcode_info->size = 1;
}
break;
case 'i':
if( strcmp( ident, "int" ) == 0 ) {
opcode_info->opcode = OPCODE_INT;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
}
break;
@@ -919,43 +934,50 @@ static OpcodeInfo *parseOpcode( void )
case 'm':
if( strcmp( ident, "jmp" ) == 0 ) {
opcode_info->opcode = OPCODE_JMP;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
}
break;
case 'e':
if( strcmp( ident, "je" ) == 0 ) {
opcode_info->opcode = OPCODE_JE;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
}
break;
case 'n':
if( strcmp( ident, "jne" ) == 0 ) {
opcode_info->opcode = OPCODE_JNE;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
}
break;
case 'b':
if( strcmp( ident, "jb" ) == 0 ) {
opcode_info->opcode = OPCODE_JB;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
} else if( strcmp( ident, "jbe" ) == 0 ) {
opcode_info->opcode = OPCODE_JBE;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
}
break;
case 'a':
if( strcmp( ident, "ja" ) == 0 ) {
opcode_info->opcode = OPCODE_JA;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
} else if( strcmp( ident, "jae" ) == 0 ) {
opcode_info->opcode = OPCODE_JAE;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
}
break;
@@ -964,43 +986,50 @@ static OpcodeInfo *parseOpcode( void )
case 'm':
if( strcmp( ident, "mov" ) == 0 ) {
opcode_info->opcode = OPCODE_MOV;
- opcode_info->nof_operands = 2;
+ opcode_info->min_operands = 2;
+ opcode_info->max_operands = 2;
opcode_info->size = 5;
} else if( strcmp( ident, "mul" ) == 0 ) {
opcode_info->opcode = OPCODE_MUL;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 2;
}
break;
case 'n':
if( strcmp( ident, "nop" ) == 0 ) {
opcode_info->opcode = OPCODE_NOP;
- opcode_info->nof_operands = 0;
+ opcode_info->min_operands = 0;
+ opcode_info->max_operands = 0;
opcode_info->size = 1;
}
break;
case 'p':
if( strcmp( ident, "push" ) == 0 ) {
opcode_info->opcode = OPCODE_PUSH;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 1;
} else if( strcmp( ident, "pop" ) == 0 ) {
opcode_info->opcode = OPCODE_POP;
- opcode_info->nof_operands = 1;
+ opcode_info->min_operands = 1;
+ opcode_info->max_operands = 1;
opcode_info->size = 1;
}
break;
case 'r':
if( strcmp( ident, "ret" ) == 0 ) {
opcode_info->opcode = OPCODE_RET;
- opcode_info->nof_operands = 0;
+ opcode_info->min_operands = 0;
+ opcode_info->max_operands = 1;
opcode_info->size = 1;
}
break;
case 's':
if( strcmp( ident, "sub" ) == 0 ) {
opcode_info->opcode = OPCODE_SUB;
- opcode_info->nof_operands = 2;
+ opcode_info->min_operands = 2;
+ opcode_info->max_operands = 2;
opcode_info->size = 2;
}
break;
@@ -1317,17 +1346,16 @@ static void parseOperands( OpcodeInfo *opcode_info )
}
}
- if( opcode_info->opcode != OPCODE_PSEUDO_DB &&
- opcode_info->opcode != OPCODE_PSEUDO_DW &&
- opcode_info->opcode != OPCODE_PSEUDO_DD &&
- nof_operands != opcode_info->nof_operands ) {
- Abort( "'%s' expects %d operand(s), %d given", opcodename[opcode_info->opcode], opcode_info->nof_operands, nof_operands );
+ if( nof_operands < opcode_info->min_operands ) {
+ Abort( "'%s' expects at least %d operand(s), only %d given", opcodename[opcode_info->opcode], opcode_info->min_operands, nof_operands );
+ }
+ if( nof_operands > opcode_info->max_operands ) {
+ Abort( "'%s' expects at most %d operand(s), but %d given", opcodename[opcode_info->opcode], opcode_info->max_operands, nof_operands );
}
switch( opcode_info->opcode ) {
case OPCODE_HLT:
case OPCODE_NOP:
- case OPCODE_RET:
break;
case OPCODE_PSEUDO_DD:
case OPCODE_PSEUDO_DW: {
@@ -1349,7 +1377,7 @@ static void parseOperands( OpcodeInfo *opcode_info )
i++;
operand_info = operand_info->next;
}
- opcode_info->nof_operands = i;
+ opcode_info->max_operands = i;
opcode_info->size = size;
} break;
case OPCODE_PSEUDO_DB: {
@@ -1367,7 +1395,7 @@ static void parseOperands( OpcodeInfo *opcode_info )
i++;
operand_info = operand_info->next;
}
- opcode_info->nof_operands = i;
+ opcode_info->max_operands = i;
opcode_info->size = size;
} break;
case OPCODE_MOV:
@@ -1434,9 +1462,19 @@ static void parseOperands( OpcodeInfo *opcode_info )
}
break;
case OPCODE_INT:
- if( opcode_info->operand->next->type != OPERAND_ABSOLUTE ) {
+ if( opcode_info->operand->type == OPERAND_ABSOLUTE ) {
/* int $80, jump to interrupt vector number */
}
+ case OPCODE_RET:
+ if( opcode_info->operand == NULL ) {
+ /* ok, no parameter return */
+ opcode_info->size = 1;
+ } else if( opcode_info->operand->type == OPERAND_ABSOLUTE ) {
+ /* return, pop N bytes from stack */
+ opcode_info->size = 3;
+ } else {
+ Abort( "'%s' expects either no operand or a number of bytes to remove from the stack", opcodename[opcode_info->opcode] );
+ }
break;
default:
Abort( "Unhandled opcode '%s' when checking operand validity", opcodename[opcode_info->opcode] );
@@ -2169,7 +2207,12 @@ static void emit_opcode( OpcodeInfo *opcode_info )
}
break;
case OPCODE_RET:
- Emit( "%c", 0xC3 );
+ if( opcode_info->operand == NULL ) {
+ Emit( "%c", 0xC3 );
+ } else if( opcode_info->operand->type == OPERAND_ABSOLUTE ) {
+ Emit( "%c", 0xC2 );
+ Emit_word_little_endian( opcode_info->operand->num );
+ }
break;
case OPCODE_PSEUDO_ASSIGN:
break;
diff --git a/ecomp-c/ec.c b/ecomp-c/ec.c
index 5d42355..f6e1926 100644
--- a/ecomp-c/ec.c
+++ b/ecomp-c/ec.c
@@ -1548,15 +1548,34 @@ static void parseParameterList( Scope *scope )
ExpressionNode *node;
Expect( S_lparen );
+ Emit( "( " );
do {
node = parseExpression( scope );
+ generate_expression_comment( node );
if( sym == S_comma ) {
sym = getSym( );
}
} while( sym != S_rparen );
Expect( S_rparen );
-
- (void)node;
+
+ Emit( ")\n" );
+
+ emit_expression_code( node, scope );
+}
+
+static void parseProcedureCall( Scope *scope )
+{
+ Symbol *symbol;
+
+ symbol = get_symbol( scope, ident );
+
+ Emit( "; CALL %s", symbol->label );
+ if( sym == S_lparen ) {
+ parseParameterList( scope );
+ } else {
+ Emit( "\n" );
+ }
+ Emit( "call %s\n", symbol->label );
}
static void parseStatement( Scope *scope )
@@ -1576,10 +1595,7 @@ static void parseStatement( Scope *scope )
Abort( "Unknown indentifier '%s'", ident );
}
if( symbol->class == SYMBOL_CLASS_PROCEDURE_TYPE ) {
- if( sym == S_lparen ) {
- parseParameterList( scope );
- }
- Emit( "call %s\n", symbol->label );
+ parseProcedureCall( scope );
} else {
parseAssignment( scope );
}
@@ -2082,7 +2098,7 @@ static void parseProcedureDeclaration( Scope *scope )
param = symbol->scope->symbol;
size_params = 0;
- offset = 0;
+ offset = -4;
while( param != NULL ) {
if( param->class == SYMBOL_CLASS_VARIABLE ) {
int size = get_size( param );
@@ -2143,7 +2159,7 @@ static void parseProcedureDeclaration( Scope *scope )
* at runtime (every time the stack is created for that procedure) */
param_or_local = symbol->scope->symbol;
while( param_or_local != NULL ) {
- if( param_or_local->class == SYMBOL_CLASS_VARIABLE ) {
+ if( param_or_local->class == SYMBOL_CLASS_VARIABLE && param_or_local->offset >= 0 ) {
/* TODO: use type here! */
int size = get_size( param_or_local );
if( param_or_local->type == integer_type || param_or_local->type == boolean_type ) {
@@ -2187,15 +2203,17 @@ static void parseProcedureDeclaration( Scope *scope )
parseStatementBlock( symbol->scope );
- /* discard locals, discard params, reset base pointer */
- if( size_locals + size_params > 0 ) {
- Emit( "mov eax, %d\n", size_locals + size_params );
+ /* discard locals, restore base pointer, discard params */
+ if( size_locals > 0 ) {
+ Emit( "mov eax, %d\n", size_locals );
Emit( "add esp, eax\n" );
}
-
Emit( "pop ebp\n" );
-
- Emit( "ret\n" );
+ if( size_params > 0 ) {
+ Emit( "ret %d\n", size_params );
+ } else {
+ Emit( "ret\n" );
+ }
}
free_scope( symbol->scope );
diff --git a/ecomp-c/test.sh b/ecomp-c/test.sh
index 014eb98..6030462 100755
--- a/ecomp-c/test.sh
+++ b/ecomp-c/test.sh
@@ -26,6 +26,7 @@ procedure_call
procedure_forward_declaration
procedure_local_variables
procedure_scoping
+procedure_call_value_parameters
example_divisors
example_divisors_array_result
example_reverse_array
diff --git a/ecomp-c/tests/procedure_call.easm b/ecomp-c/tests/procedure_call.easm
index 09daf38..013f8b2 100644
--- a/ecomp-c/tests/procedure_call.easm
+++ b/ecomp-c/tests/procedure_call.easm
@@ -16,6 +16,7 @@ mov [i], eax
pop ebp
ret
__global_0:
+; CALL __global_proc
call __global_proc
hlt
i: dd $00000000
diff --git a/ecomp-c/tests/procedure_call_value_parameters.e b/ecomp-c/tests/procedure_call_value_parameters.e
index 3b100ed..f0d6372 100644
--- a/ecomp-c/tests/procedure_call_value_parameters.e
+++ b/ecomp-c/tests/procedure_call_value_parameters.e
@@ -5,14 +5,14 @@
module procedure_call_value_parameters;
var
- i : integer := 0;
-
+ i : integer := 1;
+
procedure proc( x : integer );
var
l : integer;
begin
l := x;
- i := x;
+ i := l;
end
begin
diff --git a/ecomp-c/tests/procedure_forward_declaration.easm b/ecomp-c/tests/procedure_forward_declaration.easm
index 79ad4a4..23440e3 100644
--- a/ecomp-c/tests/procedure_forward_declaration.easm
+++ b/ecomp-c/tests/procedure_forward_declaration.easm
@@ -8,6 +8,7 @@ __global_proc1:
push ebp
push esp
pop ebp
+; CALL __global_proc2
call __global_proc2
pop ebp
ret
@@ -24,6 +25,7 @@ mov [i], eax
pop ebp
ret
__global_0:
+; CALL __global_proc1
call __global_proc1
hlt
i: dd $00000000
diff --git a/ecomp-c/tests/procedure_local_variables.easm b/ecomp-c/tests/procedure_local_variables.easm
index 88312af..1979c0c 100644
--- a/ecomp-c/tests/procedure_local_variables.easm
+++ b/ecomp-c/tests/procedure_local_variables.easm
@@ -50,6 +50,7 @@ add esp, eax
pop ebp
ret
__global_0:
+; CALL __global_proc
call __global_proc
hlt
i: dd $00000001
diff --git a/ecomp-c/tests/procedure_scoping.easm b/ecomp-c/tests/procedure_scoping.easm
index 07106a7..64a9d31 100644
--- a/ecomp-c/tests/procedure_scoping.easm
+++ b/ecomp-c/tests/procedure_scoping.easm
@@ -93,7 +93,9 @@ push eax
pop eax
pop ebx
mov [ebx], eax
+; CALL __global_A
call __global_A
+; CALL __global_B
call __global_B
hlt
y: dd $00000000