4722 lines
112 KiB
C
4722 lines
112 KiB
C
/*
|
|
* Copyright (C) 2005, David Essex, Rildo Pragana.
|
|
* Copyright (C) 2003, Rildo Pragana, Bernard Giroud.
|
|
* Copyright (C) 2002, Rildo Pragana, Jim Noeth, Bernard Giroud.
|
|
* Copyright (C) 2001, 2000, 1999, Rildo Pragana, Jim Noeth,
|
|
* David Essex, Glen Colbert.
|
|
* Copyright (C) 1993, 1991 Rildo Pragana.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Assembler Code Generator for Cobol Compiler
|
|
*
|
|
*
|
|
* Ideally this module should only contain functions which
|
|
* are assembler dependent.
|
|
*/
|
|
|
|
#include "htconfig.h"
|
|
#include "htversion.h"
|
|
#include "htcoboly.h"
|
|
#include "htcoblib.h"
|
|
#include "htglobals.h"
|
|
#include "mwindows.h"
|
|
|
|
#define decimal_char() (decimal_comma ? ',' : '.')
|
|
extern int pgm_segment;
|
|
extern int screen_io_enable;
|
|
extern int decimal_comma;
|
|
extern char currency_symbol;
|
|
char sch_convert_buf[512];
|
|
|
|
extern struct sym *screen_status_field; /* variable of crt status */
|
|
extern struct sym *cursor_field; /* variable of cursor */
|
|
extern struct lit *program_name_literal; /* literal thar holds the program name */
|
|
|
|
extern int stabs_on_sw;
|
|
|
|
extern struct lextab literal;
|
|
extern int yydebug;
|
|
extern struct sym *curr_file;
|
|
|
|
extern struct sym *curr_paragr, *curr_section;
|
|
extern struct sym *curr_field;
|
|
extern short curr_call_mode;
|
|
extern short curr_call_convention;
|
|
extern unsigned stack_offset; /* offset for variables on the stack */
|
|
/*#define SAVED_EBX_OFFSET 4*//* relative to %ebp */
|
|
extern unsigned stack_plus;
|
|
extern unsigned global_offset; /* offset for global variables (DATA) */
|
|
/*unsigned file_offset=0;*/
|
|
extern unsigned literal_offset;
|
|
#undef SEC_WORKING
|
|
#define SEC_WORKING SEC_DATA
|
|
#define SEC_RETURN_CODE SEC_DATA
|
|
extern unsigned data_offset;
|
|
/*#define data_offset global_offset*/
|
|
extern unsigned linkage_offset;
|
|
extern unsigned using_offset;
|
|
/* tmpvar_offset: for storage of temporary variables,
|
|
with space reclaimed after the current instruction*/
|
|
extern unsigned tmpvar_offset;
|
|
extern unsigned tmpvar_max;
|
|
|
|
extern unsigned last_lineno;
|
|
extern short at_procedure;
|
|
extern short refmod_slots;
|
|
static char name_buf[MAXNAMEBUF];
|
|
|
|
extern int has_linkage;
|
|
extern int module_flag;
|
|
extern int nested_flag;
|
|
|
|
extern int main_flag; /* Does it have an main entry point */
|
|
extern int main_entry_flag; /* Main entry point detected */
|
|
extern char main_entry_buf[]; /* main entry point name */
|
|
|
|
extern struct lit *spe_lit_ZE;
|
|
extern struct lit *spe_lit_SP;
|
|
extern struct lit *spe_lit_LV;
|
|
extern struct lit *spe_lit_HV;
|
|
extern struct lit *spe_lit_QU;
|
|
|
|
extern struct list *expr_list;
|
|
extern struct list *files_list;
|
|
extern struct list *disp_list;
|
|
extern struct parm_list *parameter_list;
|
|
extern struct list *fields_list;
|
|
extern struct list *last_field;
|
|
extern struct index_to_table_list *index2table;
|
|
extern struct named_sect *named_sect_list;
|
|
extern struct list *switches_list;
|
|
extern struct list *vars_list;
|
|
extern short next_available_sec_no;
|
|
extern short default_sec_no;
|
|
extern short curr_sec_no;
|
|
|
|
extern struct parm_list *chaining_list; /* chaining variables */
|
|
|
|
extern int screen_label;
|
|
extern int para_label;
|
|
extern int block_label;
|
|
extern int line_label;
|
|
extern int paragr_num;
|
|
extern int loc_label;
|
|
extern unsigned char picture[100]; /* for max 50 signs and counts */
|
|
extern int picix, piccnt, decimals, sign, v_flag, n_flag, digits, pscale;
|
|
extern int filler_num;
|
|
extern int active[37];
|
|
extern int at_linkage;
|
|
extern int stackframe_cnt;
|
|
extern int inner_stack_size;
|
|
extern char program_id[120];
|
|
extern char *pgm_label;
|
|
extern int initial_flag;
|
|
extern struct list *report_list;
|
|
static int need_desc_length_cleanup = 0;
|
|
extern int stabs_started;
|
|
|
|
extern struct sym *vartab[HASHLEN];
|
|
extern struct sym *labtab[HASHLEN];
|
|
extern struct lit *littab[HASHLEN];
|
|
|
|
/* convert control characters to don't corrupt the assembly output */
|
|
char *
|
|
sch_convert(char *s)
|
|
{
|
|
int n = 0;
|
|
char *d = sch_convert_buf;
|
|
while (*s && n++ < 45)
|
|
{
|
|
if (*s >= ' ' && *s < '\x7f')
|
|
{
|
|
*d++ = *s++;
|
|
}
|
|
else
|
|
{
|
|
*d++ = (*s++ & 0x0f) + ' ';
|
|
}
|
|
}
|
|
if (n >= 45)
|
|
{
|
|
sprintf(sch_convert_buf + 40, "...");
|
|
}
|
|
else
|
|
{
|
|
*d = 0;
|
|
}
|
|
return sch_convert_buf;
|
|
}
|
|
|
|
/*
|
|
** Code Generating Routines
|
|
*/
|
|
static char *sec_name(short sec_no)
|
|
{
|
|
struct named_sect *nsp;
|
|
|
|
for (nsp = named_sect_list; nsp != NULL;)
|
|
{
|
|
if (nsp->sec_no == sec_no)
|
|
return nsp->os_name;
|
|
nsp = nsp->next;
|
|
}
|
|
return (char *) nsp;
|
|
}
|
|
|
|
static char memref_buf[20];
|
|
char *memref(struct sym *sy)
|
|
{
|
|
if (sy->sec_no < SEC_FIRST_NAMED)
|
|
{
|
|
switch (sy->sec_no)
|
|
{
|
|
case SEC_CONST:
|
|
sprintf(memref_buf, "$c_base%d+%d", pgm_segment, sy->location);
|
|
break;
|
|
case SEC_DATA:
|
|
sprintf(memref_buf, "$w_base%d+%d", pgm_segment, sy->location);
|
|
break;
|
|
case SEC_STACK:
|
|
case SEC_ARGS:
|
|
sprintf(memref_buf, "-%d(%%ebp)", sy->location);
|
|
break;
|
|
case SEC_TEMPS:
|
|
sprintf(memref_buf, "-%u(%%esp)", sy->location);
|
|
break;
|
|
default:
|
|
/* Make sure we have an error at assembly stage */
|
|
sprintf(memref_buf, "$ww_base%d+%d #sec:%d", pgm_segment,
|
|
sy->location, sy->sec_no);
|
|
yyerror("undefined variable %s", sy->name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(memref_buf, "$%s+%d", sec_name(sy->sec_no), sy->location);
|
|
}
|
|
return memref_buf;
|
|
}
|
|
|
|
char *memrefat(struct sym *sy)
|
|
{
|
|
switch (sy->sec_no)
|
|
{
|
|
case SEC_CONST:
|
|
sprintf(memref_buf, "c_base%d+%d", pgm_segment, sy->location);
|
|
break;
|
|
case SEC_DATA:
|
|
sprintf(memref_buf, "w_base%d+%d", pgm_segment, sy->location);
|
|
break;
|
|
case SEC_STACK:
|
|
case SEC_ARGS:
|
|
sprintf(memref_buf, "-%d(%%ebp)", sy->location);
|
|
case SEC_TEMPS:
|
|
sprintf(memref_buf, "-%u(%%esp)", sy->location);
|
|
break;
|
|
default:
|
|
/* Make sure we have an error at assembly stage */
|
|
sprintf(memref_buf, "ww_base%d+%d #sec:%d", pgm_segment, sy->location,
|
|
sy->sec_no);
|
|
}
|
|
return memref_buf;
|
|
}
|
|
|
|
char *memrefd(struct sym *sy)
|
|
{
|
|
sprintf(memref_buf, "$c_base%d+%d", pgm_segment, sy->descriptor);
|
|
return memref_buf;
|
|
}
|
|
|
|
void emit_lit(char *s, int len)
|
|
{
|
|
int bcnt = 0;
|
|
while (len)
|
|
{
|
|
if (!(bcnt++ % 8))
|
|
{
|
|
if (bcnt > 1)
|
|
putc('\n',o_src);
|
|
fprintf(o_src, "\t.byte\t%d", *s++);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, ",%d", *s++);
|
|
}
|
|
len--;
|
|
}
|
|
}
|
|
|
|
void emit_lit_fill(int c, int len)
|
|
{
|
|
int bcnt = 0;
|
|
while (len)
|
|
{
|
|
if (!(bcnt++ % 8))
|
|
{
|
|
if (bcnt > 1)
|
|
putc('\n',o_src);
|
|
fprintf(o_src, "\t.byte\t%d", c);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, ",%d", c);
|
|
}
|
|
len--;
|
|
}
|
|
}
|
|
|
|
void gen_init_value(struct lit *sy, int var_len)
|
|
{
|
|
int bcnt = 0;
|
|
int len, start_len;
|
|
char *s;
|
|
char pad;
|
|
|
|
if (sy->nick)
|
|
{
|
|
s = sy->nick;
|
|
len = 1;
|
|
pad = sy->nick[0];
|
|
}
|
|
else
|
|
{
|
|
s = sy->name;
|
|
/*len=strlen(s);*/
|
|
len = sy->len;
|
|
pad = ' ';
|
|
}
|
|
if (len > var_len)
|
|
len = var_len;
|
|
start_len = len;
|
|
while (len)
|
|
{
|
|
if (!(bcnt++ % 8))
|
|
{
|
|
if (bcnt > 1)
|
|
putc('\n',o_src);
|
|
fprintf(o_src, "\t.byte\t%d", *s++);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, ",%d", *s++);
|
|
}
|
|
len--;
|
|
}
|
|
putc('\n',o_src);
|
|
if (start_len < var_len)
|
|
{
|
|
len = var_len - start_len;
|
|
bcnt = 0;
|
|
while (len)
|
|
{
|
|
if (!(bcnt++ % 8))
|
|
{
|
|
if (bcnt > 1)
|
|
putc('\n',o_src);
|
|
fprintf(o_src, "\t.byte\t%d", pad);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, ",%d", pad);
|
|
}
|
|
len--;
|
|
}
|
|
putc('\n',o_src);
|
|
}
|
|
}
|
|
|
|
void stabs_line()
|
|
{
|
|
static char *last_source_filename = NULL;
|
|
static unsigned int last_source_lineno = 0;
|
|
int new_file = TRUE; /* Is this line on a new file ? */
|
|
|
|
if (!stabs_on_sw)
|
|
return;
|
|
|
|
if (last_source_filename)
|
|
{ /* if equals new_file = 0 */
|
|
new_file = strcmp(last_source_filename, source_filename);
|
|
}
|
|
|
|
if ((!new_file) && (source_lineno == last_source_lineno))
|
|
return;
|
|
|
|
if (new_file)
|
|
fprintf(o_src, ".stabs\t\"%s\",132,0,0,.LS%d\n", source_filename,
|
|
line_label);
|
|
|
|
fprintf(o_src, ".stabn\t68,0,%d,.LS%d-Ltext_%s\n", source_lineno,
|
|
line_label, pgm_label);
|
|
fprintf(o_src, ".LS%d:\n", line_label++);
|
|
|
|
if (new_file)
|
|
{
|
|
free(last_source_filename);
|
|
last_source_filename = strdup(source_filename);
|
|
}
|
|
last_source_lineno = source_lineno;
|
|
}
|
|
|
|
void stabs_block(int end)
|
|
{
|
|
/* I just can't get this working. Let's forget it for some time. */
|
|
if (!end)
|
|
{
|
|
fprintf(o_src, ".stabs\t\".LSB%d:F(0,1)\",36,0,1,.LSB%d\n",
|
|
block_label, block_label);
|
|
fprintf(o_src, ".LSB%d:\n", block_label);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, ".LSE%d:\n", block_label);
|
|
fprintf(o_src, ".stabs\t\"\",100,0,0,.LSE%d-.LSB%d\n", block_label,
|
|
block_label);
|
|
}
|
|
}
|
|
|
|
int gen_main_rtn(void)
|
|
{
|
|
int r = 0;
|
|
|
|
#if !defined(__WINDOWS__)
|
|
char main_pgm_label[] = "main";
|
|
#else
|
|
char main_pgm_label[] = "_main";
|
|
#endif
|
|
|
|
/*
|
|
Specify the main entry point action
|
|
auto (1) - Use the first encountered 'STOP RUN' statement,
|
|
and if found, generate a program entry point.
|
|
first(2) - Use the first encountered 'PROGRAM-ID' statement,
|
|
and if found, generate a program entry point.
|
|
none (0) - Do not generate any program entry point.
|
|
(3) - Specific program entry point defined using
|
|
the '-e' CMD line option.
|
|
*/
|
|
|
|
if ((main_flag == 3) && (main_entry_flag == FALSE))
|
|
{
|
|
yyerror("Main-program entry point '%s' not found in program sequence",
|
|
main_entry_buf);
|
|
}
|
|
if (main_entry_flag == TRUE)
|
|
{
|
|
#if !defined(__WINDOWS__)
|
|
strcpy(program_id, main_entry_buf);
|
|
#else
|
|
sprintf(program_id,"%s", main_entry_buf); /* walter */
|
|
#endif
|
|
/*
|
|
if (stabs_on_sw) {
|
|
|
|
fprintf(o_src,".stabs\t\"%s\",100,0,0,Ltext_%s\n",
|
|
input_filename, pgm_label);
|
|
// fprintf(o_src,".stabs\t\"%s:F1\",36,0,0,%s\n",pgm_label,pgm_label);
|
|
fprintf(o_src,".stabs\t\"%s:F1\",36,0,0,%s\n",main_pgm_label,main_pgm_label);
|
|
fprintf(o_src,".stabs\t\"display:t2=r2;0;255;\",128,0,0,0\n");
|
|
fprintf(o_src,".stabs\t\"comp:t3=r3;-2147483648;2147483647;\",128,0,0,0\n");
|
|
fprintf(o_src,".stabs\t\"comp3:t4=r3;0;255;\",128,0,0,0\n");
|
|
fprintf(o_src,".stabs\t\"compw:t5=r5;-32768;32767;\",128,0,0,0\n");
|
|
fprintf(o_src,".stabs\t\"compb:t6=r6;-128;127;\",128,0,0,0\n");
|
|
|
|
fprintf(o_src,
|
|
".stabs\t\"compll:t7=r(0,1);0;01777777777777777777777\",128,0,0,0\n");
|
|
}
|
|
fprintf(o_src,".text\n");
|
|
|
|
if (stabs_on_sw) {
|
|
fprintf(o_src,".stabs\t\":t1\",128,0,0,0\n");
|
|
}
|
|
*/
|
|
fprintf(o_src, "\t.align 4\n");
|
|
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, ".globl %s\n\t.type\t%s,@function\n", main_pgm_label,
|
|
main_pgm_label);
|
|
#else
|
|
fprintf(o_src,".globl %s\n",pgm_label);
|
|
fprintf(o_src,"\t.def\t%s;\t.scl\t2;\t.type\t32;\t.endef\n",main_pgm_label);
|
|
#endif
|
|
fprintf(o_src, "%s:\n", main_pgm_label);
|
|
if (stabs_on_sw)
|
|
{
|
|
fprintf(o_src, ".stabs\t\":t1\",128,0,0,0\n");
|
|
}
|
|
fprintf(o_src, "\tpushl\t%%ebp\n\tmovl\t%%esp, %%ebp\n");
|
|
fprintf(o_src, "\tsubl\t$4,%%esp\n\tmovl\t$0,-4(%%ebp)\n");
|
|
fprintf(o_src, "\tmovl\t12(%%ebp),%%eax\n\tpushl\t%%eax\n");
|
|
fprintf(o_src, "\tmovl\t8(%%ebp),%%eax\n\tpushl\t%%eax\n");
|
|
asm_call("tcob_init");
|
|
fprintf(o_src, "\taddl\t$8,%%esp\n");
|
|
asm_call(program_id);
|
|
fprintf(o_src, "\tmovl\t%%eax,%%eax\n\tmovl\t%%eax,-4(%%ebp)\n");
|
|
asm_call("tcob_stop_run");
|
|
fprintf(o_src, "\tmovl\t-4(%%ebp),%%edx\n\tmovl\t%%edx,%%eax\n");
|
|
|
|
fprintf(o_src, "\tleave\n\tret\n");
|
|
|
|
/********** generate .Lfe statement ************/
|
|
fprintf(o_src, ".Lfe1:\n");
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\t.size\t%s,.Lfe1-%s\n", main_pgm_label, main_pgm_label);
|
|
#endif
|
|
|
|
}
|
|
|
|
fprintf(o_src, "\n\t.ident\t\"%s: %s\"\n", HTG_PGM_NAME, TCOB_PGM_VERSION);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
int pgm_header(char *id)
|
|
{
|
|
int r = 0;
|
|
char *sp = id;
|
|
|
|
/*
|
|
check for valid characters in PROGRAM-ID name
|
|
*/
|
|
if (!(isalpha(*sp) || (*sp == '_')))
|
|
{
|
|
r++;
|
|
yyerror("Invalid character '%c' in PROGRAM-ID name", *sp);
|
|
}
|
|
else
|
|
{
|
|
sp++;
|
|
while (*sp != '\0')
|
|
{
|
|
if (!(isalnum(*sp) || (*sp == '$') || (*sp == '.') || (*sp == '_')))
|
|
{
|
|
r++;
|
|
yyerror("Invalid character '%c' in PROGRAM-ID name", *sp);
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
#if !defined(__WINDOWS__)
|
|
strcpy(program_id, id);
|
|
#else
|
|
sprintf(program_id,"%s",id); /* walter */
|
|
#endif
|
|
|
|
/*
|
|
Specify the main entry point action
|
|
auto (1) - Use the first encountered 'STOP RUN' statement,
|
|
and if found, generate a program entry point.
|
|
first(2) - Use the first encountered 'PROGRAM-ID' statement,
|
|
and if found, generate a program entry point.
|
|
none (0) - Do not generate any program entry point.
|
|
(3) - Specific program entry point defined using the '-e' CMD line option.
|
|
*/
|
|
|
|
if ((main_flag == 3) && (main_entry_flag == FALSE))
|
|
{
|
|
if (strcmp(main_entry_buf, id) == 0)
|
|
main_entry_flag = TRUE;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
void data_trail(void)
|
|
{
|
|
/* fprintf(o_src,"_DATA ends\n\n");*/
|
|
if (refmod_slots > 0)
|
|
fprintf(o_src, "rf_base%d:\t.space\t%d\n", pgm_segment, refmod_slots
|
|
* 8);
|
|
}
|
|
|
|
/* using values : 0 = normal, 1 = using , 2 = chaining */
|
|
void proc_header(int using)
|
|
{
|
|
struct sym *sy, *sy1;
|
|
int i;
|
|
int stabs_type = '3';
|
|
|
|
/* chg_underline(program_id); */
|
|
if ((using == 1)/*|| ((using == 0 ) && (has_linkage))*/)
|
|
{ /* Is a routine */
|
|
if (!has_linkage)
|
|
{
|
|
hterror(105, TCOB_SEVERITY_ERROR,
|
|
"Using parameters should be on linkage section");
|
|
}
|
|
module_flag = TRUE;
|
|
}
|
|
if (module_flag || nested_flag)
|
|
{
|
|
pgm_label = program_id;
|
|
}
|
|
/* if ((using == 2 ) && (has_linkage)) {
|
|
hterror(106,TCOB_SEVERITY_ERROR,"A main program cannot have linkage section");
|
|
} */
|
|
|
|
/*clear_symtab();*/
|
|
if (!pgm_segment)
|
|
{
|
|
fprintf(o_src, "\t.file\t\"%s\"\n", input_filename);
|
|
fprintf(o_src, "\t.version\t\"01.01\"\ntinycobol_compiled.:\n");
|
|
/* fprintf(o_src,"\t.version\t\"%s\"\ntiny_cobol_compiled.:\n", PGM_VERSION); */
|
|
/* fprintf(o_src,"\t.version\t\"01.01\"\ntiny_cobol_compiled.:\n"); */
|
|
}
|
|
|
|
/*
|
|
// if (!pgm_segment)
|
|
// gen_main_rtn();
|
|
*/
|
|
|
|
fprintf(o_src, ".text\n");
|
|
fprintf(o_src, "Ltext_%s:\n", pgm_label);
|
|
|
|
/* insert stabs here */
|
|
if (stabs_on_sw)
|
|
{
|
|
fprintf(o_src, ".stabs\t\"%s\",100,0,0,%s\n", input_filename, pgm_label);
|
|
fprintf(o_src, ".stabs\t\"%s:F1\",36,0,0,%s\n", pgm_label, pgm_label);
|
|
|
|
/* fprintf(o_src,".stabs\t\"%s:F1\",36,0,0,%s\n",
|
|
main_pgm_label,main_pgm_label);*/
|
|
fprintf(o_src, ".stabs\t\"display:t2=r2;0;255;\",128,0,0,0\n");
|
|
fprintf(o_src,
|
|
".stabs\t\"comp:t3=r3;-2147483648;2147483647;\",128,0,0,0\n");
|
|
fprintf(o_src, ".stabs\t\"comp3:t4=r3;0;255;\",128,0,0,0\n");
|
|
fprintf(o_src, ".stabs\t\"compw:t5=r5;-32768;32767;\",128,0,0,0\n");
|
|
fprintf(o_src, ".stabs\t\"compb:t6=r6;-128;127;\",128,0,0,0\n");
|
|
/* compll (comp with 8 bytes size) is wrong. Use a dump instead */
|
|
fprintf(o_src,
|
|
".stabs\t\"compll:t7=r(0,1);0;01777777777777777777777\",128,0,0,0\n");
|
|
|
|
}
|
|
|
|
/*
|
|
if (!pgm_segment) {
|
|
if (stabs_on_sw) {
|
|
fprintf(o_src,".stabs\t\":t1\",128,0,0,0\n");
|
|
}
|
|
fprintf(o_src,"\t.align 16\n");
|
|
}
|
|
*/
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, ".globl %s\n\t.type\t%s,@function\n", pgm_label, pgm_label);
|
|
fprintf(o_src, "%s:\n", pgm_label);
|
|
#else
|
|
fprintf(o_src,".globl %s\n",pgm_label);
|
|
fprintf(o_src,"\t.def\t_%s;\t.scl\t2;\t.type\t32;\t.endef\n",pgm_label); /* walter */
|
|
fprintf(o_src,"_%s:\n",pgm_label);
|
|
#endif
|
|
if (stabs_on_sw)
|
|
{
|
|
fprintf(o_src, ".stabs\t\":t1\",128,0,0,0\n");
|
|
}
|
|
fprintf(o_src, "\tpushl\t%%ebp\n\tmovl\t%%esp, %%ebp\n");
|
|
if (stack_offset & 1)
|
|
stack_offset++;
|
|
|
|
/*
|
|
Extra 16 bytes holds search all temporary data
|
|
EOT switch, min, max boundaries and saved ebx.
|
|
Note: extra 4 bytes is to remove memory corruption problem
|
|
found in test20c.cob, probably due to boundary alignment problem.
|
|
*/
|
|
stack_offset = stack_offset + START_STACK_ADJUST;
|
|
/* add space for linkage section variables that are
|
|
not arguments of the calling program */
|
|
/*if (using)*/
|
|
stack_offset += adjust_linkage_vars(START_STACK_ADJUST);
|
|
|
|
fprintf(o_src, "\tsubl\t$%u, %%esp\n", stack_offset);
|
|
/* fprintf(o_src,"\tmovl\t%%ebx, -%d(%%ebp)\n",SAVED_EBX_OFFSET); */
|
|
fprintf(o_src, "\tmovl\t%%ebx, -%d(%%ebp)\n", stack_offset - 16);
|
|
|
|
fprintf(o_src, ".Linit_%s:\n", pgm_label);
|
|
|
|
/* Begin enter runelement */
|
|
|
|
if (decimal_comma)
|
|
{
|
|
/* fprintf(o_src,"\txorl\t$1,%%eax\n");
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src,"\tmovl\t%%eax,bDecimalComma\n");
|
|
#else
|
|
fprintf(o_src,"\tmovl\t%%eax,_bDecimalComma\n");
|
|
#endif */
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\tcall\tsetDecimalComma\n");
|
|
#else
|
|
fprintf(o_src,"\tcall\t_setDecimalComma\n");
|
|
#endif
|
|
}
|
|
if (currency_symbol != '$')
|
|
{
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\tmovb\t$%d,cCurrencySymbol\n", currency_symbol);
|
|
#else
|
|
fprintf(o_src,"\tmovb\t$%d,_cCurrencySymbol\n", currency_symbol);
|
|
#endif
|
|
}
|
|
/*
|
|
* If defined SCREEN STATUS, inform the reference in the field on the
|
|
* library
|
|
*/
|
|
if (screen_status_field != NULL)
|
|
{
|
|
if (!(screen_status_field->defined))
|
|
{
|
|
yyerror("SCREEN STATUS field '%s' not defined",
|
|
screen_status_field->name);
|
|
}
|
|
if (screen_status_field->len < 4)
|
|
{
|
|
yyerror("SCREEN STATUS field '%s' must have a size of 4",
|
|
screen_status_field->name);
|
|
}
|
|
loadloc_to_eax(screen_status_field);
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\tmovl\t%%eax, screen_status\n");
|
|
#else
|
|
fprintf(o_src,"\tmovl\t%%eax,_screen_status\n");
|
|
#endif
|
|
}
|
|
/*
|
|
* If defined CURSOR, inform the reference in the field on the
|
|
* library
|
|
*/
|
|
if (cursor_field != NULL)
|
|
{
|
|
if (!(cursor_field->defined))
|
|
{
|
|
yyerror("CURSOR field '%s' not defined", cursor_field->name);
|
|
}
|
|
if (cursor_field->len < 6)
|
|
{
|
|
yyerror("CURSOR field '%s' must have a size of 6",
|
|
cursor_field->name);
|
|
}
|
|
loadloc_to_eax(cursor_field);
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\tmovl\t%%eax, screen_cursor\n");
|
|
#else
|
|
fprintf(o_src,"\tmovl\t%%eax,_screen_cursor\n");
|
|
#endif
|
|
}
|
|
|
|
if (using == 2)
|
|
{ /* PROCEDURE DIVISION CHAINING */
|
|
/* get chaining values */
|
|
struct sym *cp;
|
|
struct parm_list *list, *tmp;
|
|
|
|
push_immed(0);
|
|
for (list = chaining_list; list != NULL;)
|
|
{
|
|
cp = (struct sym *) list->var;
|
|
gen_loadvar(cp);
|
|
tmp = list;
|
|
list = list->next;
|
|
free(tmp);
|
|
tmp = NULL;
|
|
}
|
|
asm_call("tcob_chaining");
|
|
chaining_list = NULL;
|
|
}
|
|
/*
|
|
* we save the name of the program as a literal
|
|
* for identify the run unit
|
|
*/
|
|
program_name_literal = install_lit(program_id, strlen(program_id), 0);
|
|
save_literal(program_name_literal, DTYPE_DISPLAY);
|
|
/*
|
|
* Indicate the runtime that we enter a run element
|
|
* to save / restore runtime values
|
|
*/
|
|
gen_enter_runelement(RUN_ELEMENT_ENTER);
|
|
|
|
fprintf(o_src, "\tmovl\t$s_base%d+0, %%eax\n", pgm_segment);
|
|
if (!initial_flag)
|
|
{
|
|
fprintf(o_src, "\tcmpl\t$0, 0(%%eax)\n");
|
|
fprintf(o_src, "\tjne\t.Linite_%s\n", pgm_label);
|
|
fprintf(o_src, "\tmovl\t$1, 0(%%eax)\n");
|
|
}
|
|
|
|
if (HTG_libcob)
|
|
RTL_CALL("module_init");
|
|
/********** initialize all VALUES of fields **********/
|
|
|
|
do_init_val();
|
|
|
|
if (switches_list != NULL)
|
|
gen_get_switches();
|
|
|
|
/********** dump stabs for local variables **********/
|
|
for (i = 0; i < HASHLEN; i++)
|
|
for (sy1 = vartab[i]; sy1 != NULL; sy1 = sy1->next)
|
|
for (sy = sy1; sy != NULL; sy = sy->clone)
|
|
if (sy->type != 'F' && sy->type != '8' && sy->type != 'K'
|
|
&& sy->type != 'J')
|
|
{
|
|
|
|
if (stabs_on_sw && sy->sec_no == SEC_STACK)
|
|
{
|
|
|
|
if (sy->type == DTYPE_BININT)
|
|
{
|
|
switch (symlen(sy))
|
|
{
|
|
case 1:
|
|
stabs_type = '6';
|
|
break;
|
|
case 2:
|
|
stabs_type = '5';
|
|
break;
|
|
case 4:
|
|
stabs_type = '3';
|
|
break;
|
|
case 8:
|
|
stabs_type = '7';
|
|
break;
|
|
}
|
|
fprintf(o_src, ".stabs\t\"%s:%c\",128,0,0,-%d\n",
|
|
sy->name, stabs_type, sy->location);
|
|
}
|
|
else if (sy->type == DTYPE_PACKED)
|
|
fprintf(
|
|
o_src,
|
|
".stabs\t\"%s:(1,%d)=ar3;1;%d;4\",128,0,0,-%d\n",
|
|
sy->name, sy->len, sy->len, sy->location);
|
|
else
|
|
fprintf(
|
|
o_src,
|
|
".stabs\t\"%s:(1,%d)=ar3;1;%d;2\",128,0,0,-%d\n",
|
|
sy->name, sy->len, sy->len, sy->location);
|
|
}
|
|
}
|
|
|
|
fprintf(o_src, ".Linite_%s:\n", pgm_label);
|
|
if (stabs_on_sw)
|
|
{
|
|
fprintf(o_src, ".stabn\t192,0,0,.LS%d-Ltext_%s\n", line_label,
|
|
pgm_label);
|
|
fprintf(o_src, ".stabn\t224,0,0,.LSend_%s-Ltext_%s\n", pgm_label,
|
|
pgm_label);
|
|
|
|
}
|
|
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\tleal\t%s, %%eax\n", pgm_label);
|
|
#else
|
|
fprintf(o_src,"\tleal\t_%s, %%eax\n",pgm_label);
|
|
#endif
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
fprintf(o_src, "\tleal\t.Lend_pgm_%s, %%eax\n", pgm_label);
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
stack_offset += 8; /* length of the 2 pushes above */
|
|
|
|
at_procedure++;
|
|
stabs_started++;
|
|
stabs_line();
|
|
}
|
|
|
|
void dump_descriptor_lit(struct lit *v, int len)
|
|
{
|
|
int tmplen = 0;
|
|
fprintf(o_src, "\t.long\t%d\n", (v->decimals) ? len - 1 : len);
|
|
if (HTG_libcob)
|
|
{
|
|
fprintf(o_src, "\t.long\tc_base%d+%d\n", pgm_segment, v->location); /* data pointer */
|
|
fprintf(o_src, "\t.long\tc_base%d+%d\n", pgm_segment, v->descriptor
|
|
+ CFLD_DESC_SIZE0); /* desc pointer */
|
|
fprintf(o_src, "\t.byte\t'%c',%d,%d,%d\n", v->type, v->decimals, 0,
|
|
v->all);
|
|
fprintf(o_src, "\t.long\tc_base%d+%d\n", pgm_segment, v->descriptor
|
|
+ CFLD_DESC_SIZE1); /* picture picture */
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "\t.byte\t'%c',%d,%d,%d\n", v->type, v->decimals, 0,
|
|
v->all);
|
|
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"\t.long\tc_base%d+%d\t# c_base%d+%x(hex)\n",
|
|
pgm_segment, v->descriptor+FLD_DESC_SIZE1,
|
|
pgm_segment,v->descriptor+FLD_DESC_SIZE1);
|
|
#else
|
|
fprintf(o_src, "\t.long\tc_base%d+%d\n", pgm_segment, v->descriptor
|
|
+ FLD_DESC_SIZE1); /* pointer to the picture */
|
|
#endif
|
|
}
|
|
|
|
if (v->decimals)
|
|
{
|
|
if (v->name[v->len - 1] > '9') /* signed too? */
|
|
fprintf(o_src, "\t.byte\t'S',1,'9',%d,'V',1,'9',%d,0\n", len
|
|
- v->decimals - 1, v->decimals);
|
|
else
|
|
fprintf(o_src, "\t.byte\t'9',%d,'V',1,'9',%d,0\n", len
|
|
- v->decimals - 1, v->decimals);
|
|
}
|
|
else if ((v->type == DTYPE_DISPLAY) && (v->name[v->len - 1] > '9'))
|
|
{
|
|
/* this is a signed literal, so reflect into its picture too */
|
|
fprintf(o_src, "\t.byte\t'S',1,'9',%d,0\n", len);
|
|
}
|
|
else
|
|
{
|
|
tmplen = len;
|
|
while (tmplen > 255)
|
|
{
|
|
fprintf(o_src, "\t.byte\t\'%c\',%d\n", v->type, 255);
|
|
tmplen -= 255;
|
|
}
|
|
fprintf(o_src, "\t.byte\t\'%c\',%d,0\n", v->type, tmplen);
|
|
|
|
}
|
|
}
|
|
|
|
void dump_descriptor_fld(struct sym *sy)
|
|
{
|
|
char flag;
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# Field: %s, Mem loc: %s, Desc: c_base%d+%d\n",
|
|
sy->name,memref(sy),pgm_segment,sy->descriptor );
|
|
#endif
|
|
if (sy->redefines != NULL)
|
|
sy->location = sy->redefines->location;
|
|
fprintf(o_src, "\t.long\t%d\n", sy->len);
|
|
|
|
if (HTG_libcob)
|
|
{
|
|
fprintf(o_src, "\t.long\tw_base%d+%d\n", pgm_segment, sy->location); /* data pointer */
|
|
fprintf(o_src, "\t.long\tc_base%d+%d\n", pgm_segment, sy->descriptor
|
|
+ CFLD_DESC_SIZE0); /* desc pointer */
|
|
flag = sy->flags.just_r ? 2 : 0;
|
|
flag |= (sy->flags.separate_sign ? 4 : 0);
|
|
flag |= (sy->flags.leading_sign ? 8 : 0);
|
|
flag |= (sy->flags.blank ? 16 : 0);
|
|
fprintf(o_src, "\t.byte\t'%c',%d,%d,%d\n", sy->type, sy->decimals, 0,
|
|
flag);
|
|
}
|
|
else
|
|
{
|
|
flag = sy->flags.just_r ? 2 : 0;
|
|
flag |= (sy->flags.separate_sign ? 4 : 0);
|
|
flag |= (sy->flags.leading_sign ? 8 : 0);
|
|
flag |= (sy->flags.blank ? 16 : 0);
|
|
fprintf(o_src, "\t.byte\t'%c',%d,%d,%d\n", sy->type, sy->decimals,
|
|
sy->pscale, flag);
|
|
}
|
|
if (sy->type != DTYPE_GROUP)
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"\t.long\tc_base%d+%d\t# c_base%d+%x(hex)\n",
|
|
pgm_segment,sy->pic,pgm_segment,sy->pic);
|
|
#else
|
|
fprintf(o_src, "\t.long\tc_base%d+%d\n", pgm_segment, sy->pic);
|
|
#endif
|
|
if (sy->stype == 'X')
|
|
{ /* for COMP-X generate a generic
|
|
picture */
|
|
fprintf(o_src, "\t.byte\t'9',%d\n", sym_min_pic(sy));
|
|
}
|
|
else
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < strlen(sy->picstr); i += 2)
|
|
fprintf(o_src, "\t.byte\t\'%c\',%d\n", *(sy->picstr + i),
|
|
*((unsigned char *) sy->picstr + i + 1));
|
|
}
|
|
fprintf(o_src, "\t.byte\t0\n");
|
|
}
|
|
}
|
|
|
|
/* using values : 0 = normal, 1 = using , 2 = chaining */
|
|
void proc_trail(int using)
|
|
{
|
|
struct lit *v;
|
|
struct list *list;
|
|
struct sym *sy;
|
|
/*char s[9];*/
|
|
#if !defined(__WINDOWS__)
|
|
char *pgm_label = "main";
|
|
#else
|
|
char *pgm_label = "_main";
|
|
#endif
|
|
|
|
#if 0
|
|
if (( using == 1 )/* || ((using == 0 ) && (has_linkage))*/)
|
|
{ /* Is a routine */
|
|
pgm_label = program_id;
|
|
}
|
|
#endif
|
|
if (module_flag || nested_flag)
|
|
{
|
|
pgm_label = program_id;
|
|
}
|
|
fprintf(o_src, ".Lend_pgm_%s:\n", pgm_label);
|
|
|
|
/* Screen section io cleanup (curses library). */
|
|
if (screen_io_enable != 0)
|
|
{
|
|
asm_call("tcob_do_scrio_finish");
|
|
}
|
|
|
|
asm_call("tcob_stop_run");
|
|
|
|
/* Program return code is stored in register %eax
|
|
* Note:
|
|
* The variable RETURN-CODE is a extention to the
|
|
* standard, since ANSI COBOL 85 does not support it.
|
|
*/
|
|
|
|
if ((sy = lookup(SVAR_RETURN_CODE, SYTB_VAR)) == NULL)
|
|
{
|
|
fprintf(o_src, "\tmovl\t$0, %%eax\n");
|
|
}
|
|
else
|
|
{
|
|
if (sy->sec_no == SEC_STACK)
|
|
{
|
|
fprintf(o_src, "\tleal\t-%d(%%ebp), %%edx\n", sy->location);
|
|
}
|
|
else
|
|
{
|
|
/* fprintf(o_src,"\tmovl\t$w_base+%d, %%edx\n",sy->location); */
|
|
fprintf(o_src, "\tleal\tw_base%d+%d, %%edx\n", pgm_segment,
|
|
sy->location);
|
|
}
|
|
fprintf(o_src, "\tmovl\t(%%edx), %%eax\n");
|
|
}
|
|
|
|
fprintf(o_src, "\tjmp\t.LSend_%s\n", pgm_label);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".LSend_%s:\n", pgm_label);
|
|
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
asm_call("exit");
|
|
fprintf(o_src, "\taddl\t$4,%%esp\n");
|
|
|
|
/* fprintf(o_src,"\tmovl\t-%d(%%ebp), %%ebx\n",SAVED_EBX_OFFSET); */
|
|
/* fprintf(o_src,"\tmovl\t-%d(%%ebp), %%ebx\n",stack_offset -8 - 16); */
|
|
fprintf(o_src, "\tmovl\t-%d(%%ebp), %%ebx\n", stack_offset - 24);
|
|
fprintf(o_src, "\tmov\t%%ebp,%%esp\n");
|
|
fprintf(o_src, "\tpopl\t%%ebp\n");
|
|
fprintf(o_src, "\tret\n");
|
|
|
|
/******* screen section field processing *********/
|
|
/* dump_scr_proc(); */
|
|
|
|
/********** generate .Lfe statement ************/
|
|
fprintf(o_src, ".Lfe1_%s:\n", pgm_label);
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\t.size\t%s,.Lfe1_%s-%s\n", pgm_label, pgm_label, pgm_label);
|
|
#endif
|
|
|
|
/********** generate data for literals & fields ************/
|
|
fprintf(o_src, ".data\n\t.align 4\n");
|
|
/* generate static working storage */
|
|
dump_working();
|
|
|
|
/* predefined data for special literals */
|
|
fprintf(o_src, "v_base%d:\nc_base%d:\n", pgm_segment, pgm_segment);
|
|
/**************** generate data for fields *****************/
|
|
for (list = fields_list; list != NULL; list = list->next)
|
|
{
|
|
|
|
if (((struct sym *) list->var)->type == 'F')
|
|
{ /* sort files */
|
|
char sl[21]; /* para inverter a lista */
|
|
char *s;
|
|
s = sl;
|
|
*s++ = 0; /* final da lista invertida */
|
|
sy = (struct sym *) list->var;
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# File: %s, Data loc: v_base+%d, Desc: c_base%d+%d\n",
|
|
sy->name,sy->location,pgm_segment,sy->descriptor );
|
|
#endif
|
|
sy = (struct sym *) sy->sort_data;
|
|
while (sy != NULL)
|
|
{
|
|
*s++ = (unsigned char) sy->direction;
|
|
*s++ = (unsigned char) sy->len;
|
|
sy = (struct sym *) (sy->sort_data);
|
|
}
|
|
s--;
|
|
while (*s)
|
|
{
|
|
fprintf(o_src, "\t.byte\t%u,%u\n", *(s - 1), *s);
|
|
s -= 2;
|
|
}
|
|
fprintf(o_src, "\t.byte\t0\n");
|
|
} /* end sort file */
|
|
else if (((struct sym *) list->var)->litflag)
|
|
{ /***** it is a literal *****/
|
|
int len; //, tmplen;
|
|
v = (struct lit *) list->var;
|
|
/*len = v->nick ? 1 : strlen(v->name);*/
|
|
len = v->nick ? 1 : v->len;
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# Literal: %s, Data loc: c_base%d+%d, Desc: c_base+%d\n",
|
|
sch_convert(v->name),pgm_segment,v->location,v->descriptor );
|
|
|
|
#endif
|
|
if (!v->decimals)
|
|
{ /* print literal string, w/special chars */
|
|
int i;
|
|
char *s;
|
|
if (v->nick)
|
|
{
|
|
s = v->nick;
|
|
i = 1;
|
|
}
|
|
else
|
|
{
|
|
s = v->name;
|
|
i = v->len;
|
|
}
|
|
emit_lit(s, i);
|
|
if (i)
|
|
{
|
|
fprintf(o_src, ",0\n");
|
|
}
|
|
else
|
|
{ /* null string? */
|
|
fprintf(o_src, "\t.byte\t0\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char *s;
|
|
s = v->name;
|
|
fprintf(o_src, "\t.byte\t");
|
|
while (*s && (*s != decimal_char()))
|
|
fprintf(o_src, "%d,", *s++);
|
|
s++;
|
|
while (*s)
|
|
fprintf(o_src, "%d,", *s++);
|
|
fprintf(o_src, "0\n");
|
|
}
|
|
dump_descriptor_lit(v, len);
|
|
} /* end literals */
|
|
else /*if ( ((struct sym *)list->var)->type!='D' )*/
|
|
{
|
|
/********* it is a normal field ****************/
|
|
sy = (struct sym *) list->var;
|
|
dump_descriptor_fld(sy);
|
|
} /* end normal field */
|
|
} /* end for */
|
|
|
|
/* generate data for files */
|
|
dump_fdesc();
|
|
/* dump_scr_data(); */
|
|
data_trail();
|
|
/* fprintf(o_src,"\n\t.ident\t\"TinyCOBOL: %s\"\n", PGM_VERSION); */
|
|
/* fprintf(o_src,"\n\t.ident\t\"%s: %s\"\n", HTG_PGM_NAME, TCOB_PGM_VERSION); */
|
|
dump_symbols();
|
|
} /* proc_trail */
|
|
|
|
/*
|
|
** dump all static working storage
|
|
*/
|
|
void dump_working()
|
|
{
|
|
|
|
struct sym *v, *sy;
|
|
struct list *list /*,*visited*/;
|
|
int fld_len;
|
|
int stabs_type = '3';
|
|
short cur_sec_no = SEC_WORKING;
|
|
|
|
/* fprintf(o_src,".data\n\t.align 4\n"); */
|
|
/* fprintf(o_src,"w_base:\t.long\t0\n"); */
|
|
fprintf(o_src, "w_base%d:\n", pgm_segment);
|
|
for (list = fields_list; list != NULL; list = list->next)
|
|
{
|
|
v = (struct sym *) list->var;
|
|
sy = v;
|
|
if (v->litflag)
|
|
continue;
|
|
if (v->sec_no == SEC_STACK)
|
|
continue;
|
|
if (v->type == 'F' || v->type == 'R')
|
|
continue;
|
|
fld_len = set_field_length(v, 1) * v->times;
|
|
if (v->sec_no != cur_sec_no && v->sec_no >= SEC_FIRST_NAMED)
|
|
{ /* switch of sections */
|
|
if (v->sec_no >= SEC_FIRST_NAMED)
|
|
{
|
|
/* Fix for GCC 3.x
|
|
fprintf(o_src,"\t.comm\t%s,%d,4\n",sec_name(v->sec_no), fld_len);
|
|
*/
|
|
fprintf(o_src, "\t.comm\t%s,%d\n", sec_name(v->sec_no), fld_len);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, ".text\n");
|
|
}
|
|
cur_sec_no = v->sec_no;
|
|
}
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# FIELD %s, Data Loc: %d(hex: %x) %c\n",
|
|
v->name,v->location,v->location,v->type);
|
|
#endif
|
|
if (stabs_on_sw)
|
|
{
|
|
if (sy->type == DTYPE_BININT)
|
|
{
|
|
switch (symlen(sy))
|
|
{
|
|
case 1:
|
|
stabs_type = '6';
|
|
break;
|
|
case 2:
|
|
stabs_type = '5';
|
|
break;
|
|
case 4:
|
|
stabs_type = '3';
|
|
break;
|
|
case 8:
|
|
stabs_type = '7';
|
|
break;
|
|
}
|
|
fprintf(o_src, ".stabs\t\"%s:V%c\",38,0,0,w_base%d+%d\n",
|
|
sy->name, stabs_type, pgm_segment, sy->location);
|
|
}
|
|
else if (sy->type == DTYPE_PACKED)
|
|
fprintf(
|
|
o_src,
|
|
".stabs\t\"%s:V(1,%d)=ar3;1;%d;4\",38,0,0,w_base%d+%d\n",
|
|
/* sy->name,sy->len,sy->len,sy->location); */
|
|
sy->name, sy->len, sy->len, pgm_segment, 0);
|
|
else
|
|
fprintf(
|
|
o_src,
|
|
".stabs\t\"%s:V(1,%d)=ar3;1;%d;2\",38,0,0,w_base%d+%d\n",
|
|
sy->name, sy->len, sy->len, pgm_segment, sy->location);
|
|
}
|
|
|
|
if (v->parent)
|
|
continue;
|
|
if (v->level == 66)
|
|
continue;
|
|
if (fld_len)
|
|
{ /* don't alloc dummy (zero storage) symbols */
|
|
def_field_storage(v, fld_len);
|
|
/*fprintf(o_src,"\t.space\t%d\n",fld_len);*/
|
|
}
|
|
else
|
|
{
|
|
if (v->type != DTYPE_ACCEPT_DISPLAY) /* empty fields on screen are allowed
|
|
to set line/column or color
|
|
or erase line or screen */
|
|
yyerror("Invalid picture in %s,type %c,%d,%d", v->name,
|
|
v->type, fld_len, symlen(v));
|
|
}
|
|
#if 0
|
|
if (v->son) continue; /* no space reserved for groups */
|
|
if (v->value != NULL)
|
|
{
|
|
gen_init_value(v->value,fld_len);
|
|
}
|
|
else
|
|
fprintf(o_src,"\t.ds\t%d\n",fld_len);
|
|
#endif
|
|
}
|
|
/* output tmpvar storage */
|
|
if (tmpvar_max > 0)
|
|
{
|
|
fprintf(o_src, "tv_base%d:\n", pgm_segment);
|
|
fprintf(o_src, "\t.space\t%d\n", tmpvar_max);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Use push_eax and push_ebx to generate code for
|
|
** passing parameters to the runtime functions.
|
|
** Use asm_call to call the runtime and
|
|
** automatically clean the stack.
|
|
*/
|
|
void push_immed(int i)
|
|
{
|
|
stackframe_cnt += 4;
|
|
fprintf(o_src, "\tpushl\t$%d\n", i);
|
|
}
|
|
void push_eax()
|
|
{
|
|
stackframe_cnt += 4;
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
}
|
|
|
|
void push_edx()
|
|
{
|
|
stackframe_cnt += 4;
|
|
fprintf(o_src, "\tpushl\t%%edx\n");
|
|
}
|
|
|
|
void pop_eax()
|
|
{
|
|
stackframe_cnt -= 4;
|
|
fprintf(o_src, "\tpopl\t%%eax\n");
|
|
}
|
|
|
|
void push_ebx()
|
|
{
|
|
stackframe_cnt += 4;
|
|
fprintf(o_src, "\tpushl\t%%ebx\n");
|
|
}
|
|
|
|
void push_at_ebx(struct sym *sy)
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src, "# push_at_ebx:\n");
|
|
#endif
|
|
stackframe_cnt += 4;
|
|
if (sy->type == DTYPE_BININT)
|
|
{
|
|
if (symlen(sy) == 8)
|
|
{
|
|
fprintf(o_src, "\tmovl\t4(%%ebx), %%edx\n");
|
|
fprintf(o_src, "\tmovl\t0(%%ebx), %%eax\n");
|
|
fprintf(o_src, "\tpushl\t%%edx\n");
|
|
stackframe_cnt += 4;
|
|
}
|
|
else if (symlen(sy) >= 4)
|
|
fprintf(o_src, "\tmovl\t0(%%ebx), %%eax\n");
|
|
else
|
|
fprintf(o_src, "\tmovs%cl\t0(%%ebx), %%eax\n", varsize_ch(sy));
|
|
}
|
|
else
|
|
fprintf(o_src, "\tmovl\t0(%%ebx), %%eax\n");
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
}
|
|
|
|
void push_at_eax(struct sym *sy)
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src, "# push_at_eax:\n");
|
|
#endif
|
|
stackframe_cnt += 4;
|
|
if (sy->type == DTYPE_BININT || sy->type == DTYPE_FLOAT)
|
|
{
|
|
if (symlen(sy) == 8)
|
|
{
|
|
fprintf(o_src, "\tmovl\t4(%%eax), %%edx\n");
|
|
fprintf(o_src, "\tmovl\t0(%%eax), %%eax\n");
|
|
fprintf(o_src, "\tpushl\t%%edx\n");
|
|
stackframe_cnt += 4;
|
|
}
|
|
else if (symlen(sy) >= 4)
|
|
fprintf(o_src, "\tmovl\t0(%%eax), %%eax\n");
|
|
else
|
|
fprintf(o_src, "\tmovs%cl\t0(%%eax), %%eax\n", varsize_ch(sy));
|
|
}
|
|
else
|
|
fprintf(o_src, "\tmovl\t0(%%eax), %%eax\n");
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
}
|
|
|
|
void load_at_eax(struct sym *sy)
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src, "# load_at_eax:\n");
|
|
#endif
|
|
if (sy->type == DTYPE_BININT || sy->type == DTYPE_FLOAT)
|
|
{
|
|
if (symlen(sy) == 8)
|
|
{
|
|
fprintf(o_src, "\tmovl\t4(%%eax), %%edx\n");
|
|
fprintf(o_src, "\tmovl\t0(%%eax), %%eax\n");
|
|
}
|
|
else if (symlen(sy) >= 4)
|
|
fprintf(o_src, "\tmovl\t0(%%eax), %%eax\n");
|
|
else
|
|
fprintf(o_src, "\tmovs%cl\t0(%%eax), %%eax\n", varsize_ch(sy));
|
|
}
|
|
else
|
|
fprintf(o_src, "\tmovl\t0(%%eax), %%eax\n");
|
|
}
|
|
|
|
void cleanup_rt_stack()
|
|
{
|
|
/* generate stack cleanup only if there is something to clean */
|
|
if (stackframe_cnt == 1)
|
|
fprintf(o_src, "\tpopl\t%%ecx\n");
|
|
else if (stackframe_cnt)
|
|
fprintf(o_src, "\taddl\t$%d, %%esp\n", stackframe_cnt);
|
|
stackframe_cnt = 0;
|
|
if (need_desc_length_cleanup)
|
|
{
|
|
/*#if !defined(__WINDOWS__)
|
|
fprintf(o_src,"\tcall\tcob_free_desc_list\n");
|
|
#else
|
|
fprintf(o_src,"\tcall\t_cob_free_desc_list\n");
|
|
#endif*/
|
|
tmpvar_offset = 0; /* reuse this storage area */
|
|
need_desc_length_cleanup = 0;
|
|
}
|
|
}
|
|
|
|
void asm_call(char *s)
|
|
{
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\tcall\t%s\n", s);
|
|
#else
|
|
fprintf(o_src,"\tcall\t_%s\n",s);
|
|
#endif
|
|
cleanup_rt_stack();
|
|
}
|
|
|
|
/* as asm_call but without stack cleaning */
|
|
void asm_call1(char *s)
|
|
{
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\tcall\t%s\n", s);
|
|
#else
|
|
fprintf(o_src,"\tcall\t_%s\n",s);
|
|
#endif
|
|
}
|
|
|
|
void emt_cobrtl_call(char *s, char *prefix)
|
|
{
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src, "\tcall\t%s_%s\n", prefix, s);
|
|
#else
|
|
fprintf(o_src,"\tcall\t_%s_%s\n",prefix,s);
|
|
#endif
|
|
cleanup_rt_stack();
|
|
}
|
|
|
|
int varsize_ch(struct sym *sy)
|
|
{
|
|
switch (symlen(sy))
|
|
{
|
|
case 1:
|
|
return 'b';
|
|
case 2:
|
|
return 'w';
|
|
default:
|
|
return 'l';
|
|
}
|
|
}
|
|
int find_son(struct sym *parent, struct sym *son)
|
|
{
|
|
struct sym *tmp;
|
|
for (tmp = son; tmp != NULL; tmp = tmp->parent)
|
|
{
|
|
if (tmp->parent == parent)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void gen_call_scr_process(struct sym *sy)
|
|
{
|
|
|
|
static struct sym *temp_color = NULL; /* temporay fields for */
|
|
static struct sym *temp_background = NULL; /* screen location and */
|
|
static struct sym *temp_foreground = NULL; /* colors, to be sure that */
|
|
static struct sym *temp_line = NULL; /* we call the function */
|
|
static struct sym *temp_column = NULL; /* pushing integers */
|
|
static struct sym *temp_size = NULL; /* */
|
|
|
|
struct sym *temp_parent = NULL;
|
|
struct sym *temp_son = NULL;
|
|
|
|
if ((sy->scr->line_sign != 0) || ((sy->scr->line == 0)
|
|
&& (sy->scr->line_var == NULL)))
|
|
{
|
|
/* when we have a line +/-, we have to */
|
|
/* put the cursor on the correct position */
|
|
if (!temp_line)
|
|
temp_line = define_temp_field(DTYPE_BININT, 4);
|
|
/* && (temp_parent->scr->line_sign !=0)*/
|
|
for (temp_parent = sy; temp_parent->parent; temp_parent
|
|
= temp_parent->parent) /*find the top level*/
|
|
{
|
|
if ((temp_parent->scr->line_sign == 0) && ((temp_parent->scr->line
|
|
!= 0) || (temp_parent->scr->line_var != NULL)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (temp_parent->scr->line_sign != 0)
|
|
yyerror("structure not suported '%s', invalid line",
|
|
temp_parent->name);
|
|
|
|
while (temp_parent)
|
|
{
|
|
|
|
if (temp_parent->scr->line_var)
|
|
{
|
|
gen_move(temp_parent->scr->line_var, temp_line);
|
|
push_immed(temp_parent->scr->line_sign);
|
|
value_to_eax(temp_line);
|
|
push_eax();
|
|
asm_call("tcob_go_y");
|
|
}
|
|
else
|
|
{
|
|
if (temp_parent->scr->line)
|
|
{
|
|
push_immed(temp_parent->scr->line_sign);
|
|
push_immed(temp_parent->scr->line);
|
|
asm_call("tcob_go_y");
|
|
}
|
|
}
|
|
|
|
if (find_son(temp_parent, sy))
|
|
{
|
|
temp_parent = temp_parent->son;
|
|
}
|
|
else
|
|
{
|
|
temp_parent = temp_parent->brother;
|
|
}
|
|
if (temp_parent == sy)
|
|
temp_parent = NULL;
|
|
}
|
|
}
|
|
temp_parent = NULL;
|
|
temp_son = NULL;
|
|
if (sy->scr->column_sign != 0)
|
|
{ /* when we have a line +/-, we have to */
|
|
/* put the cursor on the correct positiona */
|
|
if (!temp_column)
|
|
temp_column = define_temp_field(DTYPE_BININT, 4);
|
|
|
|
temp_son = (sy->parent)->son;
|
|
|
|
if (temp_son->scr->column_sign != 0)
|
|
yyerror("structure not suported '%s', invalid column",
|
|
temp_son->name);
|
|
|
|
if ((temp_son->scr->column == 0) && (temp_son->scr->column_var == NULL))
|
|
temp_son->scr->column = 1;
|
|
|
|
for (; temp_son != sy; temp_son = temp_son->brother)
|
|
{
|
|
if ((temp_son->scr->column == 0) && (temp_son->scr->column_var
|
|
== NULL))
|
|
{
|
|
temp_son->scr->column_sign = 1;
|
|
temp_son->scr->column = 1;
|
|
}
|
|
if (temp_son->scr->column)
|
|
{
|
|
push_immed(temp_son->scr->column_sign);
|
|
push_immed(temp_son->scr->column + temp_son->len - 1);
|
|
asm_call("tcob_go_x");
|
|
|
|
}
|
|
if (temp_son->scr->column_var)
|
|
{
|
|
gen_move(temp_son->scr->column_var, temp_column);
|
|
|
|
value_to_eax(temp_column);
|
|
fprintf(o_src, "\taddl\t$%d, %%eax\n", temp_son->len - 1);
|
|
push_immed(temp_son->scr->column_sign);
|
|
push_eax();
|
|
asm_call("tcob_go_x");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (sy->scr->color)
|
|
{
|
|
if (!temp_color)
|
|
temp_color = define_temp_field(DTYPE_BININT, 4);
|
|
gen_move(sy->scr->color, temp_color);
|
|
}
|
|
if (sy->scr->background)
|
|
{
|
|
if (!temp_background)
|
|
temp_background = define_temp_field(DTYPE_BININT, 4);
|
|
gen_move(sy->scr->background, temp_background);
|
|
}
|
|
if (sy->scr->foreground)
|
|
{
|
|
if (!temp_foreground)
|
|
temp_foreground = define_temp_field(DTYPE_BININT, 4);
|
|
gen_move(sy->scr->foreground, temp_foreground);
|
|
}
|
|
if (sy->scr->line_var)
|
|
{
|
|
if (!temp_line)
|
|
temp_line = define_temp_field(DTYPE_BININT, 4);
|
|
gen_move(sy->scr->line_var, temp_line);
|
|
}
|
|
if (sy->scr->column_var)
|
|
{
|
|
if (!temp_column)
|
|
temp_column = define_temp_field(DTYPE_BININT, 4);
|
|
gen_move(sy->scr->column_var, temp_column);
|
|
}
|
|
if (sy->scr->size)
|
|
{
|
|
if (!temp_size)
|
|
temp_size = define_temp_field(DTYPE_BININT, 4);
|
|
gen_move(sy->scr->size, temp_size);
|
|
}
|
|
|
|
gen_loadvar(sy->scr->to); /* to field */
|
|
gen_loadvar(sy->scr->from); /* from field */
|
|
gen_loadvar(sy); /* screen field */
|
|
|
|
if (sy->scr->size)
|
|
{
|
|
value_to_eax(temp_size); /* size */
|
|
push_eax();
|
|
}
|
|
else
|
|
{
|
|
push_immed(-1);
|
|
}
|
|
|
|
if (sy->scr->background)
|
|
{
|
|
value_to_eax(temp_background); /* background color */
|
|
push_eax();
|
|
}
|
|
else
|
|
{
|
|
if (sy->scr->color)
|
|
{
|
|
value_to_eax(temp_color);
|
|
fprintf(o_src, "\tand\t$0x000000F0,%%eax\n"); /* bits 4-7 */
|
|
/* color = 16 * fore-color */
|
|
fprintf(o_src, "\tshr\t$4,%%eax\n");
|
|
push_eax();
|
|
}
|
|
else
|
|
{
|
|
push_immed(-1);
|
|
}
|
|
}
|
|
|
|
if (sy->scr->foreground)
|
|
{
|
|
value_to_eax(temp_foreground); /* foreground color */
|
|
push_eax();
|
|
}
|
|
else
|
|
{
|
|
if (sy->scr->color)
|
|
{
|
|
value_to_eax(temp_color);
|
|
fprintf(o_src, "\tand\t$0x0000000F,%%eax\n"); /* bits 0-3 of color */
|
|
push_eax();
|
|
}
|
|
else
|
|
push_immed(-1);
|
|
}
|
|
push_immed(sy->scr->column_sign); /* column sign */
|
|
/* push_immed(0); *//* column sign */
|
|
if (sy->scr->column_var) /* column */
|
|
{
|
|
value_to_eax(temp_column);
|
|
push_eax();
|
|
}
|
|
else
|
|
{
|
|
push_immed(sy->scr->column);
|
|
}
|
|
push_immed(sy->scr->line_sign); /* line sign */
|
|
/*push_immed(0);*//* line sign */
|
|
if (sy->scr->line_var) /* line */
|
|
{
|
|
value_to_eax(temp_line);
|
|
push_eax();
|
|
}
|
|
else
|
|
{
|
|
push_immed(sy->scr->line);
|
|
}
|
|
|
|
if (sy->scr->color)
|
|
{
|
|
fprintf(o_src, "\tmov\t$%d,%%ebx\n", sy->scr->attr);
|
|
value_to_eax(temp_color);
|
|
fprintf(o_src, "\tand\t$0x0000FF00,%%eax\n"); /* bits 8-15 */
|
|
fprintf(o_src, "\tshr\t$8,%%eax\n");
|
|
fprintf(o_src, "\tor\t%%ebx,%%eax\n");
|
|
push_eax(); /* attributes */
|
|
|
|
}
|
|
else
|
|
{
|
|
push_immed(sy->scr->attr); /* attributes */
|
|
}
|
|
asm_call("tcob_scr_process");
|
|
}
|
|
|
|
struct math_ose *
|
|
math_on_size_error0(void)
|
|
{
|
|
struct math_ose *v;
|
|
v = malloc(sizeof(struct math_ose));
|
|
v->ose = 0; /* type of option */
|
|
v->lbl1 = 0; /* call label name 1 - on_size */
|
|
v->lbl2 = 0; /* call label name 2 - not_on_size */
|
|
v->lbl4 = loc_label++; /* determine bypass label name */
|
|
fprintf(o_src, "\tmovl\t$0,%%eax\n\tpushl\t%%eax\n"); /* reset ose cnt */
|
|
gen_jmplabel(v->lbl4); /* generate bypass jump */
|
|
return v;
|
|
}
|
|
|
|
struct math_ose *
|
|
math_on_size_error1(struct math_ose *v)
|
|
{
|
|
v->ose = loc_label++;
|
|
fprintf(o_src, ".L%d:\n", (int) v->ose);
|
|
return v;
|
|
}
|
|
|
|
void math_on_size_error2(struct math_ose *v)
|
|
{
|
|
fprintf(o_src, "\tjmp\t.L%ldR\n", v->ose);
|
|
}
|
|
|
|
void math_on_size_error3(struct math_ose *v)
|
|
{
|
|
|
|
unsigned long lbl1, lbl2;
|
|
|
|
if (v == (struct math_ose *) NULL)
|
|
return;
|
|
|
|
lbl1 = loc_label++;
|
|
|
|
/* Set the error flag */
|
|
fprintf(o_src, "\torl\t%%eax, 0(%%esp)\n");
|
|
return;
|
|
|
|
switch (v->ose)
|
|
{
|
|
case 1:
|
|
fprintf(o_src, "\torl\t%%eax, 0(%%esp)\n");
|
|
break;
|
|
|
|
case 2:
|
|
fprintf(o_src, "\tcmpl\t$0, %%eax\n");
|
|
fprintf(o_src, "\tjne\t.L%ld\n", lbl1);
|
|
fprintf(o_src, "\tleal\t.L%ld, %%eax\n", lbl1);
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
gen_jmplabel(v->lbl2);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ld:\n", lbl1);
|
|
break;
|
|
|
|
default:
|
|
lbl2 = loc_label++;
|
|
fprintf(o_src, "\tcmpl\t$0, %%eax\n");
|
|
fprintf(o_src, "\tje\t.L%ld\n", lbl1);
|
|
fprintf(o_src, "\tleal\t.L%ld, %%eax\n", lbl2);
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
gen_jmplabel(v->lbl1);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ld:\n", lbl1);
|
|
fprintf(o_src, "\tleal\t.L%ld, %%eax\n", lbl2);
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
gen_jmplabel(v->lbl2);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ld:\n", lbl2);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
struct math_ose *
|
|
math_on_size_error4(struct math_ose *v, unsigned long ty)
|
|
{
|
|
|
|
/* ose=ty; type of option */
|
|
/* lbl1 call label name 1 - on_size */
|
|
/* lbl2 call label name 2 - not_on_size */
|
|
|
|
switch (ty)
|
|
{
|
|
case 1:
|
|
v->lbl1 = v->ose;
|
|
v->ose = ty;
|
|
break;
|
|
|
|
case 2:
|
|
v->lbl2 = v->ose;
|
|
v->ose = ty;
|
|
break;
|
|
|
|
case 3:
|
|
v->lbl2 = v->ose;
|
|
v->ose = ty;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
void math_on_size_error5(struct math_ose *v)
|
|
{
|
|
unsigned long lbl1, lbl2;
|
|
|
|
if (v == (struct math_ose *) NULL)
|
|
return;
|
|
|
|
lbl1 = loc_label++;
|
|
|
|
fprintf(o_src, "\tpopl\t%%eax\n");
|
|
switch (v->ose)
|
|
{
|
|
case 1:
|
|
fprintf(o_src, "\tcmpl\t$0, %%eax\n");
|
|
fprintf(o_src, "\tje\t.L%ld\n", lbl1);
|
|
gen_jmplabel(v->lbl1);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ldR:\n", v->lbl1);
|
|
fprintf(o_src, ".L%ld:\n", lbl1);
|
|
break;
|
|
|
|
case 2:
|
|
fprintf(o_src, "\tcmpl\t$0, %%eax\n");
|
|
fprintf(o_src, "\tjne\t.L%ld\n", lbl1);
|
|
gen_jmplabel(v->lbl2);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ldR:\n", v->lbl2);
|
|
fprintf(o_src, ".L%ld:\n", lbl1);
|
|
break;
|
|
|
|
default:
|
|
lbl2 = loc_label++;
|
|
fprintf(o_src, "\tcmpl\t$0, %%eax\n");
|
|
fprintf(o_src, "\tje\t.L%ld\n", lbl1);
|
|
gen_jmplabel(v->lbl1);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ldR:\n", v->lbl1);
|
|
gen_jmplabel(lbl2);
|
|
fprintf(o_src, ".L%ld:\n", lbl1);
|
|
gen_jmplabel(v->lbl2);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ldR:\n", v->lbl2);
|
|
fprintf(o_src, ".L%ld:\n", lbl2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/******** generic structure allocation and code genertion ***********/
|
|
struct ginfo *
|
|
ginfo_container0(void)
|
|
{
|
|
struct ginfo *v;
|
|
v = malloc(sizeof(struct ginfo));
|
|
v->sel = 0; /* type of option */
|
|
v->lbl1 = 0; /* call label name 1 - true */
|
|
v->lbl2 = 0; /* call label name 2 - not true */
|
|
v->lbl3 = loc_label++; /* End of statement label name */
|
|
v->lbl4 = 0; /* not used */
|
|
v->lbl5 = loc_label++; /* determine test bypass label name */
|
|
gen_jmplabel(v->lbl5); /* generate test bypass jump */
|
|
return v;
|
|
}
|
|
|
|
struct ginfo *
|
|
ginfo_container1(struct ginfo *v)
|
|
{
|
|
v->sel = loc_label++;
|
|
fprintf(o_src, ".L%d:\n", (int) v->sel);
|
|
return v;
|
|
}
|
|
|
|
void ginfo_container2(struct ginfo *v, unsigned long ty)
|
|
{
|
|
|
|
switch (ty)
|
|
{
|
|
case 1:
|
|
v->lbl1 = v->sel;
|
|
v->sel = 0;
|
|
/*v->lbl3=loc_label++; return 1 label name */
|
|
/* gen_jmplabel(v->lbl3); generate return 1 label jump */
|
|
break;
|
|
|
|
case 2:
|
|
v->lbl2 = v->sel;
|
|
v->sel = 0;
|
|
/*v->lbl4=loc_label++; return 2 label name */
|
|
/*gen_jmplabel(v->lbl4); generate return 2 label jump */
|
|
break;
|
|
}
|
|
gen_jmplabel(v->lbl3); /* generate end label jump */
|
|
}
|
|
|
|
struct ginfo *
|
|
ginfo_container3(struct ginfo *v, unsigned long ty)
|
|
{
|
|
|
|
/* sel=ty; type of option */
|
|
/* lbl1 call label name 1 - true */
|
|
/* lbl2 call label name 2 - not true */
|
|
|
|
switch (ty)
|
|
{
|
|
case 1:
|
|
v->sel = ty;
|
|
break;
|
|
|
|
case 2:
|
|
v->sel = ty;
|
|
break;
|
|
|
|
case 3:
|
|
v->sel = ty;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%d:\n", (int) v->lbl5);
|
|
|
|
return v;
|
|
}
|
|
|
|
void ginfo_container4(struct ginfo *v)
|
|
{
|
|
|
|
switch (v->sel)
|
|
{
|
|
case 1:
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf (o_src, "# Test for At End ...\n");
|
|
#endif
|
|
fprintf(o_src, "\tcmpl\t$10, %%eax\n");
|
|
fprintf(o_src, "\tje\t.L%ld\n", v->lbl1);
|
|
/* gen_jmplabel(v->lbl1); */
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ld:\n", v->lbl3);
|
|
break;
|
|
|
|
case 2:
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf (o_src, "# Test for Not At End ...\n");
|
|
#endif
|
|
fprintf(o_src, "\tcmpl\t$10, %%eax\n");
|
|
fprintf(o_src, "\tjne\t.L%ld\n", v->lbl2);
|
|
/* gen_jmplabel(v->lbl2); */
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ld:\n", v->lbl3);
|
|
break;
|
|
|
|
default:
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf (o_src, "# Test for At End ... Not At End ...\n");
|
|
#endif
|
|
fprintf(o_src, "\tcmpl\t$10, %%eax\n");
|
|
fprintf(o_src, "\tjne\t.L%ld\n", v->lbl2);
|
|
gen_jmplabel(v->lbl1);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%ld:\n", v->lbl3);
|
|
/* gen_jmplabel(v->lbl2); */
|
|
/* fprintf(o_src,"\t.align 16\n"); */
|
|
/* fprintf(o_src,".L%ld:\n",v->lbl4); */
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void gen_test_invalid_keys(struct invalid_keys *p, struct sym *f, int fs)
|
|
{
|
|
|
|
if (p == NULL)
|
|
return;
|
|
if (p->invalid_key)
|
|
{
|
|
int lbl = loc_label++;
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf (o_src, "# Test for INVALID KEY\n");
|
|
#endif
|
|
fprintf(o_src, "\tcmp\t$%d, %%eax\n", fs);
|
|
fprintf(o_src, "\tjnz\t.L%d\n", lbl);
|
|
gen_jmplabel(p->invalid_key->lbl2);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%d:\n", lbl);
|
|
}
|
|
|
|
if (p->not_invalid_key)
|
|
{
|
|
int lbl = loc_label++;
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf (o_src, "# Test for NOT INVALID KEY\n");
|
|
#endif
|
|
fprintf(o_src, "\tcmp\t$%d, %%eax\n", fs);
|
|
fprintf(o_src, "\tjz\t.L%d\n", lbl);
|
|
gen_jmplabel(p->not_invalid_key->lbl2);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%d:\n", lbl);
|
|
}
|
|
|
|
if (p->invalid_key)
|
|
gen_dstlabel(p->invalid_key->lbl3);
|
|
if (p->not_invalid_key)
|
|
gen_dstlabel(p->not_invalid_key->lbl3);
|
|
|
|
gen_perform_decl(f);
|
|
|
|
if (p->invalid_key)
|
|
free(p->invalid_key);
|
|
if (p->not_invalid_key)
|
|
free(p->not_invalid_key);
|
|
free(p);
|
|
p = NULL;
|
|
}
|
|
|
|
void gen_subscripted(struct vref *subs)
|
|
{
|
|
struct vref *ref;
|
|
struct sym *sy;//, *var;
|
|
int outer_pushed, eax_in_use;
|
|
char op;
|
|
int stack_save;
|
|
|
|
ref = subs->next; /* here start the subscripts */
|
|
/*var =*/ sy = subs->sym; /* here our array */
|
|
op = ref->litflag;
|
|
fprintf(o_src, "# gen_subscripted\n");
|
|
outer_pushed = 0;
|
|
eax_in_use = 0;
|
|
while (ref)
|
|
{
|
|
if (((struct sym *) (ref->sym))->type == DTYPE_BININT && symlen(
|
|
ref->sym) > 4)
|
|
yywarn("binary long long subscript truncated to long");
|
|
if (eax_in_use && !outer_pushed)
|
|
{
|
|
fprintf(o_src, "\tpushl\t%%eax\t# outer_pushed\n"); /* accumulate offsets here */
|
|
outer_pushed++;
|
|
}
|
|
eax_in_use = 1;
|
|
value_to_eax(ref->sym);
|
|
if (((struct sym *) (ref->sym))->type == DTYPE_BININT && symlen(
|
|
ref->sym) > 4)
|
|
{
|
|
/* the following code is not strictly necessary: we could use %eax directly
|
|
but if a runtime check is needed, it is probably easier to implement
|
|
in the routine cob_cnv_ll2int! */
|
|
stack_save = stackframe_cnt;
|
|
stackframe_cnt = 0;
|
|
push_edx();
|
|
push_eax();
|
|
asm_call("tcob_cnv_ll2i");
|
|
stackframe_cnt = stack_save;
|
|
}
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
while (ref->litflag != ',')
|
|
{
|
|
op = ref->litflag;
|
|
ref = ref->next;
|
|
value_to_eax(ref->sym);
|
|
if (symlen(ref->sym) > 4)
|
|
{
|
|
yywarn("binary long long subscript truncated to long");
|
|
stack_save = stackframe_cnt;
|
|
stackframe_cnt = 0;
|
|
push_edx();
|
|
push_eax();
|
|
asm_call("tcob_cnv_ll2i");
|
|
stackframe_cnt = stack_save;
|
|
}
|
|
if (op == '+')
|
|
fprintf(o_src, "\taddl\t%%eax,0(%%esp)\n");
|
|
else
|
|
fprintf(o_src, "\tsubl\t%%eax,0(%%esp)\n");
|
|
}
|
|
/* find the first parent var that needs subscripting */
|
|
while (sy && !sy->occurs_flg)
|
|
sy = sy->parent;
|
|
fprintf(o_src, "\tpopl\t%%eax\n");
|
|
fprintf(o_src, "\tdecl\t%%eax\n"); /* subscript start at 1 */
|
|
if (sy->len != 1)
|
|
{
|
|
fprintf(o_src, "\tmovl\t$%d, %%edx\n", symlen(sy));
|
|
fprintf(o_src, "\timull\t%%edx\n");
|
|
}
|
|
if (outer_pushed)
|
|
{
|
|
fprintf(o_src, "\taddl\t%%eax,0(%%esp)\n");
|
|
}
|
|
if (sy)
|
|
sy = sy->parent;
|
|
ref = ref->next;
|
|
}
|
|
/*stackframe_cnt += 4;*//* update our stack frame counter */
|
|
if (outer_pushed)
|
|
fprintf(o_src, "\tpopl\t%%eax\n"); /* return offset in %eax */
|
|
}
|
|
|
|
void gen_temp_storage(int size)
|
|
{
|
|
stackframe_cnt += 4;
|
|
fprintf(o_src, "\tpushl\t$tv_base%d+%d\n", pgm_segment, tmpvar_offset);
|
|
tmpvar_offset += size;
|
|
if (tmpvar_offset > tmpvar_max)
|
|
{
|
|
tmpvar_max = tmpvar_offset;
|
|
}
|
|
}
|
|
|
|
void value_to_eax(struct sym *sy)
|
|
{
|
|
long long value;
|
|
long value2;
|
|
int stack_save;
|
|
#ifdef DEBUG_COMPILER
|
|
if (sy) fprintf(o_src,"# value_to_eax %s\n",sy->name);
|
|
#endif
|
|
if (sy == NULL)
|
|
{
|
|
fprintf(o_src, "\txorl\t%%eax,%%eax\n");
|
|
return;
|
|
}
|
|
if (sy->litflag)
|
|
{
|
|
int i, bSign = 0;
|
|
char cDigit;
|
|
/* if it's an integer, compute it now, not at runtime! */
|
|
value = 0;
|
|
/* integer's name is just it's value in ascii */
|
|
for (i = 0; (cDigit = sy->name[i]); i++)
|
|
{
|
|
if (cDigit == '}')
|
|
{
|
|
cDigit = 0;
|
|
}
|
|
else if (cDigit == '{')
|
|
{
|
|
cDigit = 0;
|
|
bSign = 1;
|
|
}
|
|
else if ((cDigit >= 'A') && (cDigit <= 'I'))
|
|
{
|
|
cDigit -= 'A' - 1;
|
|
}
|
|
else if ((cDigit >= 'J') && (cDigit <= 'R'))
|
|
{
|
|
cDigit -= 'J' - 1;
|
|
bSign = 1;
|
|
}
|
|
else
|
|
{
|
|
cDigit -= '0';
|
|
}
|
|
value = value * 10 + cDigit;
|
|
}
|
|
if (bSign)
|
|
value = -value;
|
|
fprintf(o_src, "\tmovl\t$%d,%%eax\n", (int) value);
|
|
value2 = value >> 32;
|
|
if ((value2 != 0) && (value2 != -1))
|
|
fprintf(o_src, "\tmovl\t$%d,%%edx\n", (int) value2);
|
|
}
|
|
else if (sy->type == DTYPE_BININT || sy->type == DTYPE_FLOAT)
|
|
{
|
|
/* load binary (comp) value directly */
|
|
/* %eax doesn't hold greater than 4 bytes binary types
|
|
so we use %edx to get the most significant part */
|
|
if (symlen(sy) > 4)
|
|
{
|
|
fprintf(o_src, "\tleal\t%s, %%eax\n", memrefat(sy));
|
|
fprintf(o_src, "\tmovl\t4(%%eax), %%edx\n");
|
|
fprintf(o_src, "\tmovl\t0(%%eax), %%eax\n");
|
|
}
|
|
else
|
|
{
|
|
if (symlen(sy) >= 4)
|
|
{
|
|
switch (sy->sec_no)
|
|
{
|
|
case SEC_CONST:
|
|
fprintf(o_src, "\tmovl\tc_base%d+%d, %%eax\n", pgm_segment,
|
|
sy->location);
|
|
break;
|
|
case SEC_DATA:
|
|
fprintf(o_src, "\tmovl\tw_base%d+%d, %%eax\n", pgm_segment,
|
|
sy->location);
|
|
break;
|
|
case SEC_STACK:
|
|
fprintf(o_src, "\tmovl\t-%d(%%ebp), %%eax\n", sy->location);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (sy->sec_no)
|
|
{
|
|
case SEC_CONST:
|
|
fprintf(o_src, "\tmovs%cl\tc_base%d+%d, %%eax\n",
|
|
varsize_ch(sy), pgm_segment, sy->location);
|
|
break;
|
|
case SEC_DATA:
|
|
fprintf(o_src, "\tmovs%cl\tw_base%d+%d, %%eax\n",
|
|
varsize_ch(sy), pgm_segment, sy->location);
|
|
break;
|
|
case SEC_STACK:
|
|
fprintf(o_src, "\tmovs%cl\t-%d(%%ebp), %%eax\n",
|
|
varsize_ch(sy), sy->location);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "#val to eax complex $c_base+%u, %%eax\n",
|
|
sy->descriptor);
|
|
stack_save = stackframe_cnt;
|
|
stackframe_cnt = 0;
|
|
gen_loadvar(sy);
|
|
fprintf(o_src, "#\tmovl\t$c_base+%u, %%eax\n", sy->descriptor);
|
|
asm_call("tcob_get_index");
|
|
stackframe_cnt = stack_save;
|
|
}
|
|
}
|
|
|
|
void value_to_eax_at_eax(struct sym *sy)
|
|
{
|
|
long long value;
|
|
long value2;
|
|
int stack_save;
|
|
#ifdef DEBUG_COMPILER
|
|
if (sy) fprintf(o_src,"# value_to_eax_at_eax %s\n",sy->name);
|
|
#endif
|
|
if (sy == NULL)
|
|
{
|
|
fprintf(o_src, "\txorl\t%%eax,%%eax\n");
|
|
return;
|
|
}
|
|
if (sy->litflag)
|
|
{
|
|
int i, bSign = 0;
|
|
char cDigit;
|
|
/* if it's an integer, compute it now, not at runtime! */
|
|
value = 0;
|
|
/* integer's name is just it's value in ascii */
|
|
for (i = 0; (cDigit = sy->name[i]); i++)
|
|
{
|
|
if (cDigit == '}')
|
|
{
|
|
cDigit = 0;
|
|
}
|
|
else if (cDigit == '{')
|
|
{
|
|
cDigit = 0;
|
|
bSign = 1;
|
|
}
|
|
else if ((cDigit >= 'A') && (cDigit <= 'I'))
|
|
{
|
|
cDigit -= 'A' - 1;
|
|
}
|
|
else if ((cDigit >= 'J') && (cDigit <= 'R'))
|
|
{
|
|
cDigit -= 'J' - 1;
|
|
bSign = 1;
|
|
}
|
|
else
|
|
{
|
|
cDigit -= '0';
|
|
}
|
|
value = value * 10 + cDigit;
|
|
}
|
|
if (bSign)
|
|
value = -value;
|
|
fprintf(o_src, "\tmovl\t$%d,%%eax\n", (int) value);
|
|
value2 = value >> 32;
|
|
if ((value2 != 0) && (value2 != -1))
|
|
fprintf(o_src, "\tmovl\t$%d,%%edx\n", (int) value2);
|
|
}
|
|
else if (sy->type == DTYPE_BININT || sy->type == DTYPE_FLOAT)
|
|
{
|
|
/* load binary (comp) value directly */
|
|
/* %eax doesn't hold greater than 4 bytes binary types
|
|
so we use %edx to get the most significant part */
|
|
if (symlen(sy) > 4)
|
|
{
|
|
fprintf(o_src, "\tmovl\t4(%%eax), %%edx\n");
|
|
fprintf(o_src, "\tmovl\t0(%%eax), %%eax\n");
|
|
}
|
|
else
|
|
{
|
|
if (symlen(sy) >= 4)
|
|
{
|
|
switch (sy->sec_no)
|
|
{
|
|
case SEC_CONST:
|
|
fprintf(o_src, "\tmovl\tc_base%d+%d, %%eax\n", pgm_segment,
|
|
sy->location);
|
|
break;
|
|
case SEC_DATA:
|
|
fprintf(o_src, "\tmovl\tw_base%d+%d, %%eax\n", pgm_segment,
|
|
sy->location);
|
|
break;
|
|
case SEC_STACK:
|
|
fprintf(o_src, "\tmovl\t-%d(%%ebp), %%eax\n", sy->location);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (sy->sec_no)
|
|
{
|
|
case SEC_CONST:
|
|
fprintf(o_src, "\tmovs%cl\tc_base%d+%d, %%eax\n",
|
|
varsize_ch(sy), pgm_segment, sy->location);
|
|
break;
|
|
case SEC_DATA:
|
|
fprintf(o_src, "\tmovs%cl\tw_base%d+%d, %%eax\n",
|
|
varsize_ch(sy), pgm_segment, sy->location);
|
|
break;
|
|
case SEC_STACK:
|
|
fprintf(o_src, "\tmovs%cl\t-%d(%%ebp), %%eax\n",
|
|
varsize_ch(sy), sy->location);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "#val to eax complex $c_base+%u, %%eax\n",
|
|
sy->descriptor);
|
|
stack_save = stackframe_cnt;
|
|
stackframe_cnt = 0;
|
|
/* gen_loadvar(sy); */
|
|
push_eax();
|
|
gen_loaddesc(sy);
|
|
asm_call("tcob_get_index");
|
|
stackframe_cnt = stack_save;
|
|
}
|
|
}
|
|
|
|
/* load address for normal (file/working-storage) or linkage variable */
|
|
void load_address(struct sym *var)
|
|
{
|
|
unsigned base, locoff;
|
|
struct sym *tmp;
|
|
if (!var->litflag && var->linkage_flg)
|
|
{
|
|
tmp = var;
|
|
while (tmp->linkage_flg == 1)
|
|
tmp = tmp->parent;
|
|
if (tmp == 0)
|
|
hterror(103, 8, "linkage section broken");
|
|
base = tmp->linkage_flg;
|
|
locoff = tmp->location - var->location;
|
|
fprintf(o_src, "\tmovl\t%d(%%ebp), %%eax\n", base);
|
|
if (locoff)
|
|
{
|
|
fprintf(o_src, "\taddl\t$%d, %%eax\n", locoff);
|
|
}
|
|
}
|
|
/* else if (!var->litflag) { */
|
|
else if (var->sec_no == SEC_STACK)
|
|
{
|
|
fprintf(o_src, "\tleal\t%s, %%eax\n", memref(var));
|
|
}
|
|
else
|
|
{
|
|
if (var->sec_no == SEC_DATA)
|
|
#if 0
|
|
fprintf(o_src,"\tlea%c\tw_base+%d, %%ebx\n",
|
|
The result is expected in %eax not %ebx
|
|
fprintf(o_src,"\tlea%c\tw_base+%d, %%eax\n",
|
|
varsize_ch(var),var->location);
|
|
#endif
|
|
fprintf(o_src, "\tleal\tw_base%d+%d, %%eax\n", pgm_segment,
|
|
var->location);
|
|
else if (var->sec_no == SEC_CONST)
|
|
#if 0
|
|
fprintf(o_src,"\tlea%c\tc_base+%d, %%ebx\n",
|
|
fprintf(o_src,"\tlea%c\tc_base+%d, %%eax\n",
|
|
varsize_ch(var),var->location);
|
|
#endif
|
|
fprintf(o_src, "\tleal\tc_base%d+%d, %%eax\n", pgm_segment,
|
|
var->location);
|
|
/* this is not the same! I need an address here, not the value.
|
|
fprintf(o_src,"\tmovl\t%s, %%eax\n",memref(var));*/
|
|
}
|
|
}
|
|
|
|
/* load in cpureg ("eax","ebx"...) location for normal
|
|
(file/working-storage) or linkage variable */
|
|
void load_location(struct sym *var, char *cpureg)
|
|
{
|
|
unsigned base, locoff;
|
|
struct sym *tmp;
|
|
if (var == NULL)
|
|
{
|
|
fprintf(o_src, "\txorl\t%%%s,%%%s\n", cpureg, cpureg);
|
|
return;
|
|
}
|
|
if (!var->litflag && var->linkage_flg)
|
|
{
|
|
tmp = var;
|
|
while (tmp->linkage_flg == 1)
|
|
tmp = tmp->parent;
|
|
if (tmp == 0)
|
|
hterror(103, 8, "linkage section broken");
|
|
base = tmp->linkage_flg;
|
|
locoff = var->location - tmp->location;
|
|
fprintf(o_src, "\tmovl\t%d(%%ebp), %%%s\n", base, cpureg);
|
|
if (locoff)
|
|
{
|
|
fprintf(o_src, "\taddl\t$%d, %%%s\n", locoff, cpureg);
|
|
}
|
|
}
|
|
/* else if (!var->litflag) { */
|
|
else if (var->sec_no == SEC_STACK)
|
|
{
|
|
fprintf(o_src, "\tleal\t%s, %%%s\n", memref(var), cpureg);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "\tmovl\t%s, %%%s\n", memref(var), cpureg);
|
|
|
|
}
|
|
}
|
|
|
|
void loadloc_to_eax(struct sym *sy_p)
|
|
{
|
|
unsigned base, locoff;
|
|
struct sym *sy = sy_p, *var, *tmp;
|
|
if (sy == NULL)
|
|
{
|
|
hterror(104, 8, "*** fatal error: variable undefined!\n");
|
|
return;
|
|
}
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"#gen_loadloc litflg %d\n",sy->litflag);
|
|
#endif
|
|
if (sy->litflag == 4)
|
|
sy = ((struct refmod *) sy)->sym; /* temp bypass */
|
|
if (sy->litflag == 2)
|
|
{
|
|
gen_subscripted((struct vref *) sy);
|
|
var = (struct sym *) ((struct vref *) sy)->sym;
|
|
if (var->linkage_flg)
|
|
{
|
|
tmp = var;
|
|
while (tmp->linkage_flg == 1)
|
|
tmp = tmp->parent;
|
|
if (tmp == 0)
|
|
yyerror("linkage section broken");
|
|
base = tmp->linkage_flg;
|
|
/*locoff = tmp->location - var->location;*/
|
|
locoff = var->location - tmp->location;
|
|
/*if (symlen(var)>=4)*/
|
|
fprintf(o_src, "\tmovl\t%d(%%ebp), %%ebx\n", base);
|
|
/*else
|
|
fprintf(o_src,"\tmovs%cl %d(%%ebp), %%ebx\n",
|
|
varsize_ch(var),base);*/
|
|
if (locoff)
|
|
{
|
|
fprintf(o_src, "\taddl\t$%d, %%ebx\n", locoff);
|
|
}
|
|
fprintf(o_src, "\taddl\t%%ebx, %%eax\n");
|
|
}
|
|
else
|
|
{
|
|
if (var->sec_no == SEC_STACK)
|
|
fprintf(o_src, "\tleal\t%s, %%ebx\n", memref(var));
|
|
else
|
|
{
|
|
if (var->sec_no == SEC_DATA)
|
|
/* fprintf(o_src,"\tlea%c\tw_base+%d, %%ebx\n",
|
|
varsize_ch(var),var->location); */
|
|
fprintf(o_src, "\tleal\tw_base%d+%d, %%ebx\n", pgm_segment,
|
|
var->location);
|
|
else if (var->sec_no == SEC_CONST)
|
|
/* fprintf(o_src,"\tlea%c\tc_base+%d, %%ebx\n",
|
|
varsize_ch(var),var->location); */
|
|
fprintf(o_src, "\tleal\tc_base%d+%d, %%ebx\n", pgm_segment,
|
|
var->location);
|
|
}
|
|
|
|
fprintf(o_src, "\taddl\t%%ebx,%%eax\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
load_location(sy, "eax");
|
|
}
|
|
/* At that stage, the address is ready in %eax; do we need
|
|
to correct it because of RefMod's? */
|
|
if (sy_p->litflag == 4)
|
|
{ /* should avoid all that if literal 1 */
|
|
struct refmod * rfp = (struct refmod *) sy_p;
|
|
fprintf(o_src, "\tmovl\t%%eax, %%ebx\n");
|
|
value_to_eax((rfp->off));
|
|
fprintf(o_src, "\tdecl\t%%eax\n");
|
|
fprintf(o_src, "\taddl\t%%ebx, %%eax\n");
|
|
}
|
|
}
|
|
|
|
/* store variable pointer in eax to sy.
|
|
sy must be a pointer or a linkage section 01/77 variable */
|
|
void set_ptr(struct sym *sy)
|
|
{
|
|
/*unsigned base;*/
|
|
if (sy->litflag == 0 && sy->linkage_flg)
|
|
{
|
|
if (sy->linkage_flg == 1)
|
|
{
|
|
yyerror("only level 01 or 77 linkage vars may be set");
|
|
return;
|
|
}
|
|
fprintf(o_src, "\tmovl\t%%eax,%d(%%ebp)\n", sy->linkage_flg);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (sy->litflag == 0)
|
|
{
|
|
load_location(sy, "ebx");
|
|
fprintf(o_src, "\tmovl\t%%eax,0(%%ebx)\n");
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "\tpushl\t%%eax\t# saving ptr value\n");
|
|
loadloc_to_eax(sy);
|
|
fprintf(o_src, "\tmovl\t%%eax,%%ebx\n");
|
|
fprintf(o_src, "\tpopl\t%%eax\n");
|
|
fprintf(o_src, "\tmovl\t%%eax,0(%%ebx)\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void gen_loaddesc1(struct sym *sy, int variable_length)
|
|
{
|
|
struct sym *var;
|
|
var = sy;
|
|
if (var->litflag == 2 || var->litflag == 4)
|
|
{
|
|
var = ((struct vref *) var)->sym;
|
|
if (var->litflag == 2)
|
|
{
|
|
var = ((struct vref *) var)->sym;
|
|
}
|
|
}
|
|
if (sy->litflag == 4)
|
|
{
|
|
struct refmod * rflp = (struct refmod *) sy;
|
|
struct sym * syl = rflp->len;
|
|
if (syl == NULL)
|
|
{
|
|
fprintf(o_src, "# corrected length EOV\n");
|
|
value_to_eax(rflp->off);
|
|
fprintf(o_src, "\tnegl\t%%eax\n");
|
|
fprintf(o_src, "\taddl\t$%d, %%eax\n", symlen(var));
|
|
fprintf(o_src, "\tincl\t%%eax\n");
|
|
fprintf(o_src, "\tmovl\t%%eax, rf_base%d+%d\n", pgm_segment,
|
|
rflp->slot * 8);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "# corrected length %s\n", syl->name);
|
|
if (syl->litflag == 1)
|
|
{
|
|
/* the statement below does not always work if the literal
|
|
begins with a zero: as thinks it is an octal number.
|
|
We should really convert the "name" into a proper
|
|
value. (See bug #704519)*/
|
|
/*fprintf(o_src,"\tmovl\t$%s, rf_base%d+%d\n",
|
|
syl->name,pgm_segment, rflp->slot*8);*/
|
|
value_to_eax(syl);
|
|
fprintf(o_src, "\tmovl\t%%eax, rf_base%d+%d\n", pgm_segment,
|
|
rflp->slot * 8);
|
|
}
|
|
else
|
|
{
|
|
value_to_eax(syl);
|
|
fprintf(o_src, "\tmovl\t%%eax, rf_base%d+%d\n", pgm_segment,
|
|
rflp->slot * 8);
|
|
}
|
|
}
|
|
fprintf(o_src, "\tmovl\t$'%c', rf_base%d+%d\n", 'X' /*'G'*/,
|
|
pgm_segment, rflp->slot * 8 + 4);
|
|
fprintf(o_src, "\tmovl\t$rf_base%d+%d, %%eax\n", pgm_segment,
|
|
rflp->slot * 8);
|
|
}
|
|
else
|
|
{
|
|
/* adjust its length if there is a variable size item inside */
|
|
if (variable_length && (get_variable_item(sy) != NULL))
|
|
{
|
|
adjust_desc_length(sy);
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"\tmovl\t%s, %%eax\t# descriptor of [%s]\n",
|
|
memrefd(var),sch_convert(var->name));
|
|
#else
|
|
fprintf(o_src, "\tmovl\t%s, %%eax\n", memrefd(var));
|
|
#endif
|
|
}
|
|
}
|
|
push_eax();
|
|
}
|
|
|
|
/* quick fix for generating a suitable descriptor for
|
|
ACCEPT of numeric fields (screen/curses enabled) when
|
|
refmods are used */
|
|
void gen_loaddesc2(struct sym *sy, int variable_length)
|
|
{
|
|
struct sym *var;
|
|
int adjust;
|
|
|
|
var = sy;
|
|
adjust = 0;
|
|
|
|
if (var->litflag == 2 || var->litflag == 4)
|
|
{
|
|
var = ((struct vref *) var)->sym;
|
|
if (var->litflag == 2)
|
|
{
|
|
var = ((struct vref *) var)->sym;
|
|
}
|
|
}
|
|
if (sy->litflag == 4)
|
|
{
|
|
struct refmod * rflp = (struct refmod *) sy;
|
|
struct sym * syl = rflp->len;
|
|
/* if (var->type == '9') */
|
|
if (var->type != 'X')
|
|
{
|
|
fprintf(o_src, "\tmovl\t$%d, %%eax\n", var->len);
|
|
adjust++;
|
|
}
|
|
else
|
|
{
|
|
if (syl == NULL)
|
|
{
|
|
fprintf(o_src, "#corrected length EOV\n");
|
|
value_to_eax(rflp->off);
|
|
fprintf(o_src, "\tnegl\t%%eax\n");
|
|
fprintf(o_src, "\taddl\t$%d, %%eax\n", symlen(var));
|
|
fprintf(o_src, "\tincl\t%%eax\n");
|
|
fprintf(o_src, "\tmovl\t%%eax, rf_base%d+%d\n", pgm_segment,
|
|
rflp->slot * 8);
|
|
}
|
|
else
|
|
{
|
|
if (syl->litflag == 1)
|
|
{
|
|
/* the statement below does not always work if the literal
|
|
begins with a zero: as thinks it is an octal number.
|
|
We should really convert the "name" into a proper
|
|
value. (See bug #704519)*/
|
|
/*fprintf(o_src,"\tmovl\t$%s, rf_base%d+%d\n",
|
|
syl->name,pgm_segment, rflp->slot*8);*/
|
|
value_to_eax(syl);
|
|
fprintf(o_src, "\tmovl\t%%eax, rf_base%d+%d\n",
|
|
pgm_segment, rflp->slot * 8);
|
|
}
|
|
else
|
|
{
|
|
value_to_eax(syl);
|
|
fprintf(o_src, "\tmovl\t%%eax, rf_base%d+%d\n",
|
|
pgm_segment, rflp->slot * 8);
|
|
}
|
|
}
|
|
}
|
|
fprintf(o_src, "\tmovl\t$'X', rf_base%d+%d\n", pgm_segment, rflp->slot
|
|
* 8 + 4);
|
|
fprintf(o_src, "\tmovl\t$rf_base%d+%d, %%eax\n", pgm_segment,
|
|
rflp->slot * 8);
|
|
}
|
|
else
|
|
adjust++;
|
|
if (adjust)
|
|
{
|
|
/* adjust its length if there is a variable size item inside */
|
|
if (variable_length && (get_variable_item(sy) != NULL))
|
|
{
|
|
adjust_desc_length(sy);
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"\tmovl\t%s, %%eax\t# descriptor of [%s]\n",
|
|
memrefd(var),sch_convert(var->name));
|
|
#else
|
|
fprintf(o_src, "\tmovl\t%s, %%eax\n", memrefd(var));
|
|
#endif
|
|
}
|
|
}
|
|
push_eax();
|
|
}
|
|
|
|
void gen_loadval(struct sym *sy)
|
|
{
|
|
unsigned base, locoff;
|
|
struct sym *var;
|
|
struct sym *tmp = sy;
|
|
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"#gen_loadval\n");
|
|
#endif
|
|
if (sy == NULL)
|
|
{
|
|
hterror(104, 8, "*** fatal error: variable undefined!\n");
|
|
return;
|
|
}
|
|
if (sy->litflag == 2)
|
|
{
|
|
gen_subscripted((struct vref *) sy);
|
|
var = (struct sym *) ((struct vref *) sy)->sym;
|
|
if (var->linkage_flg)
|
|
{
|
|
tmp = var;
|
|
while (tmp->linkage_flg == 1)
|
|
tmp = tmp->parent;
|
|
if (tmp == 0)
|
|
yyerror("linkage section broken");
|
|
base = tmp->linkage_flg;
|
|
locoff = tmp->location - var->location;
|
|
if (symlen(var) >= 4)
|
|
fprintf(o_src, "\tmovl\t%d(%%ebp), %%ebx\n", base);
|
|
else
|
|
fprintf(o_src, "\tmovs%cl %d(%%ebp), %%ebx\n", varsize_ch(var),
|
|
base);
|
|
if (locoff)
|
|
{
|
|
fprintf(o_src, "\taddl\t$%d, %%ebx\n", locoff);
|
|
}
|
|
fprintf(o_src, "\taddl\t%%eax, %%ebx\n");
|
|
fprintf(o_src, "\tmovl\t%%ebx, %%eax\n");
|
|
tmp = var;
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "\tleal\t%s, %%ebx\n", memrefat(var));
|
|
fprintf(o_src, "\taddl\t%%ebx,%%eax\n");
|
|
tmp = var;
|
|
}
|
|
}
|
|
else if (sy->litflag == 0)
|
|
{
|
|
tmp = sy;
|
|
load_address(tmp);
|
|
}
|
|
if (tmp->type == DTYPE_DISPLAY)
|
|
{
|
|
value_to_eax_at_eax(tmp);
|
|
return;
|
|
}
|
|
if (sy->litflag == 1)
|
|
value_to_eax(sy);
|
|
else
|
|
load_at_eax(tmp);
|
|
}
|
|
|
|
void gen_pushval(struct sym *sy)
|
|
{
|
|
unsigned base, locoff;
|
|
struct sym *var, *tmp;
|
|
if (sy == NULL)
|
|
{
|
|
hterror(104, 8, "*** fatal error: variable undefined!\n");
|
|
return;
|
|
}
|
|
if (sy->litflag == 2)
|
|
{
|
|
gen_subscripted((struct vref *) sy);
|
|
var = (struct sym *) ((struct vref *) sy)->sym;
|
|
if (var->linkage_flg)
|
|
{
|
|
tmp = var;
|
|
while (tmp->linkage_flg == 1)
|
|
tmp = tmp->parent;
|
|
if (tmp == 0)
|
|
yyerror("linkage section broken");
|
|
base = tmp->linkage_flg;
|
|
locoff = tmp->location - var->location;
|
|
if (symlen(var) >= 4)
|
|
fprintf(o_src, "\tmovl\t%d(%%ebp), %%ebx\n", base);
|
|
else
|
|
fprintf(o_src, "\tmovs%cl\t%d(%%ebp), %%ebx\n",
|
|
varsize_ch(var), base);
|
|
if (locoff)
|
|
{
|
|
fprintf(o_src, "\taddl\t$%d, %%ebx\n", locoff);
|
|
}
|
|
fprintf(o_src, "\taddl\t%%eax, %%ebx\n");
|
|
push_ebx();
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "\tleal\t-%d(%%ebp), %%ebx\n", var->location);
|
|
fprintf(o_src, "\taddl\t%%ebx,%%eax\n");
|
|
push_at_eax(var);
|
|
}
|
|
}
|
|
else if (sy->litflag == 0)
|
|
{
|
|
load_address(sy);
|
|
push_at_eax(sy);
|
|
}
|
|
else
|
|
{
|
|
/*value_to_eax(sy);*/
|
|
}
|
|
}
|
|
|
|
void gen_store_fnres(struct sym *sy)
|
|
{
|
|
if (sy == NULL)
|
|
return;
|
|
switch (sy->type)
|
|
{
|
|
case DTYPE_BININT:
|
|
switch (symlen(sy))
|
|
{
|
|
case 4:
|
|
fprintf(o_src, "\tmovl\t%%eax, %s\n", memrefat(sy));
|
|
break;
|
|
case 2:
|
|
fprintf(o_src, "\tmov\t%%ax, %s\n", memrefat(sy));
|
|
break;
|
|
}
|
|
;
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
}
|
|
|
|
/* The following functions will be activated when we change from
|
|
defining the outermost group to define each elementary item. */
|
|
/*void init_field_val( struct sym *sy ) {
|
|
struct lit *val=(struct lit *)sy->value;
|
|
/ *if (val->type != 'X' || sy->type != 'X' || val->nick != NULL) {* /
|
|
/ * can't call gen_move passing a NULL pointer!
|
|
This happens because it is a PROCEDURE DIVISION USING VAR ...* /
|
|
/ * if (val != NULL)
|
|
gen_move_init((struct sym *)val,sy);
|
|
/ *}* /
|
|
/ *}*/
|
|
|
|
void def_field_storage(struct sym *sy, int fld_len)
|
|
{
|
|
/*struct lit *val=(struct lit *)sy->value;
|
|
int vlen;
|
|
if (val == NULL ||
|
|
val->type != 'X' || sy->type != 'X' || val->nick != NULL) {*/
|
|
fprintf(o_src, "\t.space\t%d\n", fld_len);
|
|
/*}
|
|
else {
|
|
vlen = strlen(val->name);
|
|
if (vlen < fld_len) {
|
|
emit_lit( val->name, vlen );
|
|
fprintf(o_src,"\n");
|
|
emit_lit_fill( ' ', fld_len - vlen );
|
|
fprintf(o_src,"\n");
|
|
}
|
|
else {
|
|
emit_lit( val->name, fld_len );
|
|
fprintf(o_src,"\n");
|
|
}
|
|
}*/
|
|
}
|
|
|
|
void gen_set(struct sym *idx, int which, struct sym *var, int adrof_idx,
|
|
int adrof_var)
|
|
{
|
|
struct vref *ref;
|
|
// struct vrange *vr;
|
|
struct sym *sy = idx;
|
|
|
|
if (idx->litflag == 4)
|
|
sy = ((struct refmod *) idx)->sym;
|
|
else if (idx->litflag == 2)
|
|
sy = (struct sym *) ((struct vref *) idx)->sym;
|
|
|
|
if (sy->type == '8')
|
|
{ /* conditional? */
|
|
// vr = sy->refmod_redef.vr;
|
|
/*
|
|
If 88 level value has more than one entry,
|
|
default to first value entry.
|
|
|
|
if ((vr!=NULL) || (sy->value2 != sy->value)) {
|
|
yyerror("conditional is not unique");
|
|
return;
|
|
}
|
|
*/
|
|
if (idx->litflag == 2)
|
|
{
|
|
ref = malloc(sizeof(struct vref));
|
|
ref->litflag = 2;
|
|
ref->sym = sy->parent;
|
|
ref->next = ((struct vref *) idx)->next;
|
|
gen_move((struct sym *) sy->value, (struct sym *) ref);
|
|
free(ref);
|
|
ref = NULL;
|
|
}
|
|
else
|
|
{
|
|
gen_move((struct sym *) sy->value, sy->parent);
|
|
}
|
|
return;
|
|
}
|
|
/* we are setting a value to true but is not a level 88 */
|
|
if ((int) var == 1)
|
|
{
|
|
yyerror("not a level 88 '%s'", sy->name);
|
|
return;
|
|
}
|
|
|
|
if (sy->type == DTYPE_BININT && sy->ix_desc != NULL)
|
|
{ /* switch? */
|
|
gen_set_switch(var, sy);
|
|
return;
|
|
}
|
|
|
|
if (sy->flags.is_pointer || adrof_idx)
|
|
{ /* pointer? */
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# set %s to %s\n",idx?idx->name:"(null)",
|
|
var?var->name:"(null)");
|
|
fprintf(o_src,"# adrof_idx: %d, adrof_var: %d\n",
|
|
adrof_idx, adrof_var);
|
|
#endif
|
|
if (which != SET_TO)
|
|
{
|
|
yyerror("only SET TO work with pointers");
|
|
return;
|
|
}
|
|
if (adrof_idx && !(idx->linkage_flg))
|
|
{
|
|
yyerror("only linkage variables may be set to a new address");
|
|
return;
|
|
}
|
|
if (adrof_var)
|
|
{
|
|
/*load_location(var,"eax");*/
|
|
loadloc_to_eax(var);
|
|
set_ptr(idx);
|
|
}
|
|
else
|
|
{
|
|
/* value_to_eax(var); <-- this is not working! */
|
|
if (var == NULL)
|
|
{
|
|
fprintf(o_src, "\txorl\t%%eax,%%eax\n");
|
|
}
|
|
else
|
|
{
|
|
load_location(var, "ebx");
|
|
fprintf(o_src, "\tmovl\t0(%%ebx),%%eax\n");
|
|
}
|
|
set_ptr(idx);
|
|
}
|
|
return;
|
|
}
|
|
/******** it is not a pointer, so must be an index ********/
|
|
|
|
/* first get the second operand */
|
|
if (idx->type != DTYPE_BININT)
|
|
{
|
|
gen_set_complex(var, which, idx);
|
|
return;
|
|
}
|
|
fprintf(o_src, "# SET %s \n", idx->name);
|
|
|
|
if (symlen(idx) > 4)
|
|
yywarn("index variable truncated to long");
|
|
|
|
gen_loadval(var);
|
|
|
|
switch (which)
|
|
{
|
|
case SET_TO: /* just move this value */
|
|
fprintf(o_src, "\tmov%c\t%%eax, %s\n", varsize_ch(idx), memrefat(idx));
|
|
break;
|
|
case SET_UP_BY: /* we need to add this value to the index */
|
|
fprintf(o_src, "\tadd%c\t%%eax, %s\n", varsize_ch(idx), memrefat(idx));
|
|
break;
|
|
case SET_DOWN_BY:
|
|
fprintf(o_src, "\tsub%c\t%%eax, %s\n", varsize_ch(idx), memrefat(idx));
|
|
break;
|
|
default:
|
|
yyerror("SET option unavailable");
|
|
}
|
|
}
|
|
|
|
int push_selection_subject_copy(int level, struct selsubject *ssbj, int stkadd,
|
|
int objtype)
|
|
{
|
|
struct selsubject *p;
|
|
|
|
/* find the target subject */
|
|
while (level--)
|
|
ssbj = ssbj->next;
|
|
|
|
/* calculate the subject address */
|
|
for (p = ssbj->next; p; p = p->next)
|
|
{
|
|
if (ssbj->type == SSUBJ_EXPR)
|
|
{
|
|
stkadd += 8;
|
|
}
|
|
else if (ssbj->type == SSUBJ_COND)
|
|
{
|
|
stkadd += 4;
|
|
}
|
|
}
|
|
|
|
/* push expressions to the stack, conditions in %eax */
|
|
switch (ssbj->type)
|
|
{
|
|
case SSUBJ_COND:
|
|
fprintf(o_src, "\tmovl %d(%%esp),%%eax\n", stkadd);
|
|
break;
|
|
case SSUBJ_EXPR:
|
|
fprintf(o_src, "\tpushl %d(%%esp)\n", stkadd + 4);
|
|
fprintf(o_src, "\tpushl %d(%%esp)\n", stkadd + 4);
|
|
break;
|
|
case SSUBJ_STR:
|
|
gen_loadvar(ssbj->var);
|
|
break;
|
|
case FALSE:
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void gen_when_check(int level, struct selsubject *ssbj, int type, int endcase,
|
|
struct sym *var)
|
|
{
|
|
int invert = 0;
|
|
int stkadd = 0;
|
|
int cleanup, bypass;
|
|
fprintf(o_src,
|
|
"# WHEN check: level=%d, subject->type=%d, object type=%d\n",
|
|
level, ssbj->type, type);
|
|
stkadd += selection_object_size(type);
|
|
|
|
/* check if compatible subject/object found */
|
|
switch (selection_subject_type(level, ssbj))
|
|
{
|
|
case SSUBJ_STR:
|
|
if ((type != SOBJ_STR) && (type != SOBJ_NEGSTR) && (type != SOBJ_ANY))
|
|
{
|
|
yyerror("incompatible selection object");
|
|
}
|
|
break;
|
|
case SSUBJ_EXPR:
|
|
if ((type != SOBJ_EXPR) && (type != SOBJ_NEGEXPR) && (type
|
|
!= SOBJ_RANGE) && (type != SOBJ_NEGRANGE)
|
|
&& (type != SOBJ_COND) && (type != SOBJ_NEGCOND) && (type
|
|
!= SOBJ_ANY))
|
|
{
|
|
yyerror("incompatible selection object");
|
|
}
|
|
break;
|
|
case SSUBJ_COND:
|
|
if ((type != SOBJ_TRUE) && (type != SOBJ_FALSE) && (type != SOBJ_ANY))
|
|
{
|
|
yyerror("incompatible selection object");
|
|
}
|
|
break;
|
|
case SSUBJ_FALSE:
|
|
invert = 1;
|
|
case SSUBJ_TRUE:
|
|
if ((type != SOBJ_COND) && (type != SOBJ_NEGCOND) && (type != SOBJ_ANY))
|
|
{
|
|
yyerror("incompatible selection object");
|
|
}
|
|
}
|
|
|
|
/* perform the actual tests */
|
|
switch (type)
|
|
{
|
|
case SOBJ_STR:
|
|
case SOBJ_NEGSTR:
|
|
fprintf(o_src, "# SOBJ_STR or SOBJ_NEGSTR\n");
|
|
push_selection_subject_copy(level, ssbj, stkadd, type);
|
|
gen_loadvar(var);
|
|
asm_call("tcob_compare");
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n"); /* equal */
|
|
if (type == SOBJ_STR)
|
|
fprintf(o_src, "\tjnz\t.L%d\n", endcase);
|
|
else
|
|
fprintf(o_src, "\tjz\t.L%d\n", endcase);
|
|
break;
|
|
case SOBJ_EXPR:
|
|
case SOBJ_NEGEXPR:
|
|
fprintf(o_src, "# SOBJ_EXPR or SOBJ_NEGEXPR\n");
|
|
push_selection_subject_copy(level, ssbj, stkadd, type);
|
|
gen_compare_exp(EQUAL);
|
|
if (type == SOBJ_EXPR)
|
|
fprintf(o_src, "\tjnz\t.L%d\n", endcase);
|
|
else
|
|
fprintf(o_src, "\tjz\t.L%d\n", endcase);
|
|
break;
|
|
case SOBJ_RANGE:
|
|
case SOBJ_NEGRANGE:
|
|
cleanup = loc_label++;
|
|
bypass = loc_label++;
|
|
fprintf(o_src, "# SOBJ_RANGE or SOBJ_NEGRANGE\n");
|
|
push_selection_subject_copy(level, ssbj, stkadd, type);
|
|
gen_compare_exp(LESS);
|
|
if (type == SOBJ_RANGE)
|
|
fprintf(o_src, "\tjz\t.L%d\n", cleanup);
|
|
else
|
|
fprintf(o_src, "\tjnz\t.L%d\n", cleanup);
|
|
stkadd -= 8;
|
|
push_selection_subject_copy(level, ssbj, stkadd, type);
|
|
gen_compare_exp(GREATER);
|
|
if (type == SOBJ_RANGE)
|
|
fprintf(o_src, "\tjz\t.L%d\n", endcase);
|
|
else
|
|
fprintf(o_src, "\tjnz\t.L%d\n", endcase);
|
|
/* cleanup unused double at stack */
|
|
fprintf(o_src, "\tjmp\t.L%d\n", bypass);
|
|
fprintf(o_src, ".L%d:\taddl\t$8, %%esp\n", cleanup);
|
|
fprintf(o_src, "\tjmp\t.L%d\n", endcase);
|
|
fprintf(o_src, ".L%d:\n", bypass);
|
|
break;
|
|
case SOBJ_COND:
|
|
case SOBJ_NEGCOND:
|
|
/*invert=push_selection_subject_copy(level,ssbj,stkadd,type);*/
|
|
if (type == SOBJ_COND)
|
|
fprintf(o_src, "\tjnz\t.L%d\n", endcase);
|
|
else
|
|
fprintf(o_src, "\tjz\t.L%d\n", endcase);
|
|
break;
|
|
case SOBJ_ANY: /* no tests needed, just accept */
|
|
break;
|
|
case SOBJ_TRUE:
|
|
invert = push_selection_subject_copy(level, ssbj, stkadd, type);
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n");
|
|
if (invert)
|
|
fprintf(o_src, "\tjz\t.L%d\n", endcase);
|
|
else
|
|
fprintf(o_src, "\tjnz\t.L%d\n", endcase);
|
|
break;
|
|
case SOBJ_FALSE:
|
|
invert = push_selection_subject_copy(level, ssbj, stkadd, type);
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n");
|
|
if (invert)
|
|
fprintf(o_src, "\tjnz\t.L%d\n", endcase);
|
|
else
|
|
fprintf(o_src, "\tjz\t.L%d\n", endcase);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void gen_bypass_when_case(int bypass)
|
|
{
|
|
if (bypass)
|
|
{
|
|
fprintf(o_src, ".L%d:\n", bypass);
|
|
}
|
|
}
|
|
|
|
int gen_end_when(int n, int endcase, int sentence)
|
|
{
|
|
int lab;
|
|
if (sentence)
|
|
{
|
|
fprintf(o_src, "\tjmp\t.L%d\t# end WHEN\n", n);
|
|
lab = 0;
|
|
}
|
|
else
|
|
{
|
|
lab = loc_label++;
|
|
fprintf(o_src, "\tjmp\t.L%d\t# bypass WHEN test\n", lab);
|
|
}
|
|
fprintf(o_src, ".L%d:\n", endcase);
|
|
return lab;
|
|
}
|
|
|
|
void push_condition()
|
|
{
|
|
fprintf(o_src, "\tpushl\t%%eax\t# push_condition\n");
|
|
}
|
|
|
|
void gen_goto_depending(struct list *l, struct sym *sy)
|
|
{
|
|
struct list *tmp;
|
|
struct sym *var;
|
|
|
|
var = sy;
|
|
if (var->litflag == 2 || var->litflag == 4)
|
|
{
|
|
var = ((struct vref *) var)->sym;
|
|
if (var->litflag == 2)
|
|
var = ((struct vref *) var)->sym;
|
|
}
|
|
if (!HTG_libcob)
|
|
gen_loadloc(sy);
|
|
gen_loaddesc(sy);
|
|
|
|
asm_call("tcob_get_index"); /* this will return %eax with var's value */
|
|
for (tmp = l; tmp != NULL; tmp = tmp->next)
|
|
{
|
|
fprintf(o_src, "\tdecl\t%%eax\n");
|
|
fprintf(o_src, "\tjz\t.LB_%s\n", label_name((struct sym *) tmp->var));
|
|
}
|
|
free_list(l);
|
|
}
|
|
|
|
void gen_goto(struct list *l)
|
|
{
|
|
struct sym *sy = (struct sym *) l->var;
|
|
if (inner_stack_size)
|
|
{
|
|
fprintf(o_src, "\taddl\t$%d, %%esp\n", inner_stack_size);
|
|
}
|
|
stabs_line();
|
|
fprintf(o_src, "\tjmp\t.LB_%s\n", label_name(sy));
|
|
if (l->next)
|
|
{
|
|
yyerror("GOTO only allows one target");
|
|
}
|
|
free_list(l);
|
|
}
|
|
|
|
int gen_check_zero()
|
|
{
|
|
int i = loc_label++;
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n");
|
|
fprintf(o_src, "\tjz\t.L%d\n", i);
|
|
stabs_line();
|
|
return i;
|
|
}
|
|
|
|
unsigned long gen_at_end(int status)
|
|
{
|
|
int i, j;
|
|
union label_def label;
|
|
i = loc_label++;
|
|
j = loc_label++;
|
|
|
|
fprintf(o_src, "\tcmp\t$%d, %%eax\n", status);
|
|
fprintf(o_src, "\tjz\t.L%d\n", j);
|
|
fprintf(o_src, "\tjmp\t.L%d\n", i);
|
|
|
|
/* fprintf(o_src,"L%d:\n",j); */
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%d:\n", j);
|
|
|
|
stabs_line();
|
|
label.l.n = i;
|
|
label.l.off = label.l.defined = 0;
|
|
return label.x;
|
|
}
|
|
|
|
unsigned long gen_testif(void)
|
|
{
|
|
int i, j;
|
|
union label_def label;
|
|
i = loc_label++;
|
|
j = loc_label++;
|
|
fprintf(o_src, "\tjz\t.L%d\n", j);
|
|
fprintf(o_src, "\tjmp\t.L%d\n", i);
|
|
|
|
/* fprintf(o_src,"L%d:\n",j); */
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%d:\n", j);
|
|
|
|
stabs_line();
|
|
|
|
label.l.n = i;
|
|
label.l.off = label.l.defined = 0;
|
|
return label.x;
|
|
}
|
|
|
|
void gen_not(void)
|
|
{
|
|
int i, j;
|
|
i = loc_label++;
|
|
j = loc_label++;
|
|
|
|
fprintf(o_src, "\tjz\t.L%d\n", i);
|
|
fprintf(o_src, "\txorl\t%%eax,%%eax\n");
|
|
fprintf(o_src, "\tjmp\t.L%d\n", j);
|
|
fprintf(o_src, ".L%d:\tincl\t%%eax\n", i);
|
|
|
|
/* fprintf(o_src,"L%d:\n",j); */
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%d:\n", j);
|
|
|
|
stabs_line();
|
|
}
|
|
|
|
unsigned long gen_andstart(void)
|
|
{
|
|
int i;
|
|
union label_def label;
|
|
i = loc_label++;
|
|
fprintf(o_src, "\tjnz\t.L%d\n", i);
|
|
label.l.n = i;
|
|
label.l.off = label.l.defined = 0;
|
|
return label.x;
|
|
}
|
|
|
|
unsigned long gen_orstart(void)
|
|
{
|
|
int i;
|
|
union label_def label;
|
|
i = loc_label++;
|
|
fprintf(o_src, "\tjz\t.L%d\n", i);
|
|
label.l.n = i;
|
|
label.l.off = label.l.defined = 0;
|
|
return label.x;
|
|
}
|
|
|
|
void gen_dstlabel(unsigned long lbl)
|
|
{
|
|
char slab[32];
|
|
union label_def label;
|
|
label.x = lbl;
|
|
sprintf(slab, ".L%d", label.l.n);
|
|
fprintf(o_src, ".L%d:\n", label.l.n);
|
|
stabs_line();
|
|
}
|
|
|
|
unsigned long gen_passlabel(void)
|
|
{
|
|
int i;
|
|
union label_def label;
|
|
i = loc_label++;
|
|
fprintf(o_src, "\tjmp\t.L%d\n", i);
|
|
label.l.off = label.l.defined = 0;
|
|
label.l.n = i;
|
|
return label.x;
|
|
}
|
|
|
|
unsigned long gen_marklabel(void)
|
|
{
|
|
int i;
|
|
union label_def label;
|
|
i = loc_label++;
|
|
fprintf(o_src, ".L%d:\n", i);
|
|
stabs_line();
|
|
label.l.defined = 1;
|
|
label.l.n = i;
|
|
return label.x;
|
|
}
|
|
|
|
void gen_jmplabel(unsigned long lbl)
|
|
{
|
|
union label_def label;
|
|
label.x = lbl;
|
|
fprintf(o_src, "\tjmp\t.L%d\n", label.l.n);
|
|
}
|
|
|
|
void gen_push_int(struct sym *sy)
|
|
{
|
|
/* gen_loadloc( sy ); */
|
|
/*/ fprintf(o_src,"\tmovl\t$c_base%d+%u, %%eax\n",
|
|
pgm_segment,sy->descriptor); */
|
|
gen_loadvar(sy);
|
|
asm_call("tcob_get_index");
|
|
/* this must be done without calling push_eax */
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
}
|
|
|
|
void gen_perform_test_counter(unsigned long lbl)
|
|
{
|
|
union label_def label;
|
|
label.x = lbl;
|
|
fprintf(o_src, "\tcmpl\t$0,0(%%esp)\n");
|
|
fprintf(o_src, "\tjle\t.L%dE\n", label.l.n);
|
|
}
|
|
|
|
void gen_perform_times(unsigned long lbl)
|
|
{
|
|
union label_def label;
|
|
label.x = lbl;
|
|
fprintf(o_src, "\tdecl\t0(%%esp)\n");
|
|
fprintf(o_src, "\tjnz\t.L%d\n", label.l.n);
|
|
fprintf(o_src, ".L%dE:\tpopl\t%%ecx\n", label.l.n);
|
|
}
|
|
|
|
void gen_perform_thru(struct sym *s1, struct sym *s2)
|
|
{
|
|
/*stabs_block(0);*/
|
|
if (s2 == NULL)
|
|
s2 = s1;
|
|
fprintf(o_src, "\tleal\t.L%d, %%eax\n", loc_label);
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
fprintf(o_src, "\tleal\t.LB_%s, %%eax\n", label_name(s1));
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
fprintf(o_src, "\tleal\t.LE_%s, %%eax\n", label_name(s2));
|
|
/* fprintf(o_src,"\tpushl\t%%ax\n");*/
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
fprintf(o_src, "\tjmp\t.LB_%s\n", label_name(s1));
|
|
|
|
fprintf(o_src, "\t.align 16\n");
|
|
fprintf(o_src, ".L%d:\n", loc_label++);
|
|
/*stabs_block(1);*/
|
|
stabs_line();
|
|
}
|
|
|
|
/* increment loop index, check for end */
|
|
void gen_SearchLoopCheck(unsigned long lbl5, struct sym *syidx,
|
|
struct sym *sytbl)
|
|
{
|
|
|
|
/*struct sym *sy1, *sy2;*/
|
|
struct lit *v;
|
|
char tblmax[21];
|
|
|
|
strcpy(tblmax, "1");
|
|
v = (struct lit *) install(tblmax, SYTB_LIT, 0);
|
|
save_literal(v, DTYPE_DISPLAY);
|
|
|
|
gen_add((struct sym *) v, syidx, 0);
|
|
|
|
sprintf(tblmax, "%d", sytbl->times);
|
|
v = (struct lit *) install(tblmax, SYTB_LIT, 0);
|
|
save_literal(v, DTYPE_DISPLAY);
|
|
|
|
gen_compare(syidx, GREATER, (struct sym *) v);
|
|
fprintf(o_src, "\tjz\t.L%ld\n", lbl5);
|
|
|
|
stabs_line();
|
|
}
|
|
|
|
void gen_SearchAllLoopCheck(unsigned long lbl3, struct sym *syidx,
|
|
struct sym *sytbl, struct sym *syvar, unsigned long lstart,
|
|
unsigned long lend)
|
|
{
|
|
|
|
struct sym *sy1;
|
|
struct vref *vr1;
|
|
struct index_to_table_list *it1, *it2;
|
|
unsigned long l1, l2, l3, l4, l5, l6;
|
|
|
|
l1 = loc_label++;
|
|
l2 = loc_label++;
|
|
l3 = loc_label++;
|
|
l4 = loc_label++;
|
|
l5 = loc_label++;
|
|
l6 = loc_label++;
|
|
|
|
it1 = index2table;
|
|
it2 = NULL;
|
|
while (it1 != NULL)
|
|
{
|
|
if (strcmp(it1->tablename, sytbl->name) == 0)
|
|
{
|
|
it2 = it1;
|
|
it1 = NULL;
|
|
}
|
|
else
|
|
{
|
|
it1 = it1->next;
|
|
}
|
|
}
|
|
|
|
if (it2 == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((it2->seq != '1') && (it2->seq != '2'))
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_COMPILER
|
|
if (it2->seq == '1')
|
|
{
|
|
fprintf(o_src,"#gen_SearchAllLoopCheck: sequence for table %s is %c=ASCENDING\n",
|
|
sytbl->name, it2->seq);
|
|
}
|
|
if (it2->seq == '2')
|
|
{
|
|
fprintf(o_src,"#gen_SearchAllLoopCheck: sequence for table %s is %c=DESCENDING\n",
|
|
sytbl->name, it2->seq);
|
|
}
|
|
fprintf(o_src,"#gen_SearchAllLoopCheck: l1=L%lu, l2=L%lu, l3=L%lu, l4=L%lu, l5=L%lu, l6=L%lu\n",
|
|
l1, l2, l3, l4, l5, l6);
|
|
#endif
|
|
|
|
vr1 = create_subscript(syidx);
|
|
sy1 = (struct sym *) create_subscripted_var(sytbl, vr1);
|
|
|
|
/* table sort sequence: '0' = none, '1' = ASCENDING, '2' = DESCENDING */
|
|
|
|
/* if ((bu - bl) > 1) */
|
|
fprintf(o_src, "\tmovl\t-%d(%%ebp), %%eax\n", stack_offset - 12);
|
|
fprintf(o_src, "\tsubl\t-%d(%%ebp), %%eax\n", stack_offset - 8);
|
|
|
|
fprintf(o_src, "\tcmpl\t$1, %%eax\n");
|
|
fprintf(o_src, "\tjle .L%ld\n", l1);
|
|
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
/* if (itbl1 > in) { *//* '2' = DESCENDING */
|
|
if (it2->seq == '2')
|
|
{
|
|
gen_compare(sy1, GREATER, syvar);
|
|
fprintf(o_src, "\tjnz\t.L%ld\n", l2);
|
|
}
|
|
else
|
|
{
|
|
gen_compare(sy1, LESS, syvar);
|
|
fprintf(o_src, "\tjnz\t.L%ld\n", l2);
|
|
}
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
/* bl = idx + 1; */
|
|
/* fprintf(o_src,"\tmovl\t-%d(%%ebp), %%eax\n", syidx->location); */
|
|
fprintf(o_src, "\tmovl\t%s, %%eax\n", memrefat(syidx));
|
|
fprintf(o_src, "\taddl\t$1, %%eax\n");
|
|
fprintf(o_src, "\tmovl\t%%eax, -%d(%%ebp)\n", stack_offset - 8);
|
|
|
|
gen_jmplabel(l3);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
/* else { */
|
|
gen_dstlabel(l2);
|
|
|
|
/* bu = idx - 1; */
|
|
/* fprintf(o_src,"\tmovl\t-%d(%%ebp), %%eax\n", syidx->location); */
|
|
fprintf(o_src, "\tmovl\t%s, %%eax\n", memrefat(syidx));
|
|
fprintf(o_src, "\tsubl\t$1, %%eax\n");
|
|
fprintf(o_src, "\tmovl\t%%eax, -%d(%%ebp)\n", stack_offset - 12);
|
|
|
|
gen_dstlabel(l3);
|
|
|
|
/* idx = ((bu - bl)/2 + bl); */
|
|
fprintf(o_src, "\tmovl\t-%d(%%ebp), %%eax\n", stack_offset - 12);
|
|
fprintf(o_src, "\tsubl\t-%d(%%ebp), %%eax\n", stack_offset - 8);
|
|
fprintf(o_src, "\tmovl\t%%eax, %%edx\n");
|
|
fprintf(o_src, "\tsarl\t$31, %%edx\n");
|
|
fprintf(o_src, "\tmovl\t%%edx, %%ecx\n");
|
|
fprintf(o_src, "\tsarl\t$31, %%ecx\n");
|
|
fprintf(o_src, "\tleal\t(%%ecx,%%eax), %%edx\n");
|
|
fprintf(o_src, "\tmovl\t%%edx, %%eax\n");
|
|
fprintf(o_src, "\tsarl\t$1, %%eax\n");
|
|
fprintf(o_src, "\taddl\t-%d(%%ebp), %%eax\n", stack_offset - 8);
|
|
/* fprintf(o_src,"\tmovl\t%%eax, -%d(%%ebp)\n", syidx->location); */
|
|
fprintf(o_src, "\tmovl\t%%eax, %s\n", memrefat(syidx));
|
|
|
|
gen_jmplabel(l6);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
/* else { *//* l1 */
|
|
gen_dstlabel(l1);
|
|
|
|
if (it2->seq == '2')
|
|
{
|
|
/* if (itbl1 > in) { */
|
|
gen_compare(sy1, GREATER, syvar);
|
|
fprintf(o_src, "\tjnz\t.L%ld\n", l4);
|
|
}
|
|
else
|
|
{
|
|
/* if (itbl1 < in) { */
|
|
gen_compare(sy1, LESS, syvar);
|
|
fprintf(o_src, "\tjnz\t.L%ld\n", l4);
|
|
}
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
/* if (bu > idx) { */
|
|
/* fprintf(o_src,"\tmovl\t-%d(%%ebp), %%eax\n", syidx->location); */
|
|
fprintf(o_src, "\tmovl\t%s, %%eax\n", memrefat(syidx));
|
|
fprintf(o_src, "\tcmpl\t%%eax, -%d(%%ebp)\n", stack_offset - 12);
|
|
|
|
fprintf(o_src, "\tjle\t.L%ld\n", l5);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
/* idx = bu; */
|
|
fprintf(o_src, "\tmovl\t-%d(%%ebp), %%eax\n", stack_offset - 12);
|
|
/* fprintf(o_src,"\tmovl\t%%eax, -%d(%%ebp)\n", syidx->location); */
|
|
fprintf(o_src, "\tmovl\t%%eax, %s\n", memrefat(syidx));
|
|
|
|
gen_jmplabel(l6);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
/* else { */
|
|
gen_dstlabel(l5);
|
|
|
|
/* r++; */
|
|
fprintf(o_src, "\taddl\t$1, -%d(%%ebp)\n", stack_offset - 4);
|
|
|
|
gen_jmplabel(l6);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
|
|
/* } */
|
|
/* } */
|
|
/* else { */
|
|
gen_dstlabel(l4);
|
|
|
|
/* r++; */
|
|
fprintf(o_src, "\taddl\t$1, -%d(%%ebp)\n", stack_offset - 4);
|
|
|
|
gen_dstlabel(l6);
|
|
|
|
fprintf(o_src, "\tmovl\t-%d(%%ebp), %%eax\n", stack_offset - 4);
|
|
fprintf(o_src, "\tcmpl\t$1, %%eax\n");
|
|
fprintf(o_src, "\tjz\t.L%ld\n", lbl3);
|
|
|
|
gen_jmplabel(lstart);
|
|
fprintf(o_src, "\t.align 16\n");
|
|
gen_dstlabel(lend);
|
|
|
|
stabs_line();
|
|
}
|
|
|
|
void Initialize_SearchAll_Boundaries(struct sym *sy, struct sym *syidx)
|
|
{
|
|
int i;
|
|
struct lit *v;
|
|
char tblmax[21];
|
|
struct index_to_table_list *i2t1, *i2t2;
|
|
|
|
i = sy->times / 2;
|
|
|
|
sprintf(tblmax, "%d", i);
|
|
v = (struct lit *) install(tblmax, SYTB_LIT, 0);
|
|
#ifdef DEBUG_COMPILER
|
|
if (v->type)
|
|
{ /* not already saved */
|
|
fprintf(o_src,"#Initialize_SearchAll_Boundaries: literal is saved: %s\n", tblmax);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src,"#Initialize_SearchAll_Boundaries: literal not saved: %s\n", tblmax);
|
|
}
|
|
#endif
|
|
|
|
save_literal(v, DTYPE_DISPLAY);
|
|
gen_move((struct sym *) v, syidx);
|
|
|
|
fprintf(o_src, "\tmovl\t$0, %%eax\n");
|
|
fprintf(o_src, "\tmovl\t%%eax,-%d(%%ebp)\n", stack_offset - 4);
|
|
|
|
fprintf(o_src, "\tmovl\t$1, %%eax\n");
|
|
fprintf(o_src, "\tmovl\t%%eax,-%d(%%ebp)\n", stack_offset - 8);
|
|
|
|
fprintf(o_src, "\tmovl\t$%d, %%eax\n", sy->times);
|
|
fprintf(o_src, "\tmovl\t%%eax,-%d(%%ebp)\n", stack_offset - 12);
|
|
|
|
i2t2 = NULL;
|
|
i2t1 = index2table;
|
|
while (i2t1 != NULL)
|
|
{
|
|
if (strcmp(i2t1->tablename, sy->name) == 0)
|
|
{
|
|
if (i2t1->seq != '0')
|
|
{
|
|
i2t2 = i2t1;
|
|
}
|
|
i2t1 = NULL;
|
|
}
|
|
else
|
|
{
|
|
i2t1 = i2t1->next;
|
|
}
|
|
}
|
|
|
|
if (i2t2 == NULL)
|
|
{
|
|
yyerror("Undefined sort order and key for table");
|
|
}
|
|
|
|
}
|
|
|
|
void resolve_labels()
|
|
{
|
|
struct sym *sy = NULL, *sy1 = NULL, *sy2 = NULL;
|
|
int i, def;
|
|
fprintf(o_src, "# resolving paragraphs/sections labels\n");
|
|
for (i = 0; i < HASHLEN; i++)
|
|
{
|
|
for (sy = labtab[i]; sy != NULL; sy = sy->next)
|
|
{
|
|
fprintf(o_src, "## 1 %d,%d\n", HASHLEN, i);
|
|
|
|
if (sy == NULL)
|
|
continue;
|
|
|
|
fprintf(o_src, "## 2\n");
|
|
fprintf(o_src, "## %s\n", sy->name);
|
|
if (sy->type == 'f')
|
|
continue;
|
|
sy1 = sy;
|
|
while (sy1)
|
|
{
|
|
if (sy1->defined == 2)
|
|
{ /*Labels used but not defined */
|
|
/* fprintf(stderr,"%s of %s: used but not defined \n",sy1->name,(sy1->parent)?sy1->parent->name:NULL); */
|
|
def = 0;
|
|
sy2 = sy;
|
|
/* find if we have already defined the label on
|
|
the same section (same parent) */
|
|
while (sy2)
|
|
{
|
|
if ((sy2->defined == 1) && (sy1->parent)
|
|
&& (sy2->parent) && (sy1->parent->name)
|
|
&& (sy2->parent->name))
|
|
{
|
|
if (!strcmp(sy1->parent->name, sy2->parent->name))
|
|
{
|
|
def++;
|
|
/*fprintf(stderr,"%s of %s: found on the same section \n",sy2->name,(sy2->parent)?sy2->parent->name:NULL);*/
|
|
break;
|
|
}
|
|
}
|
|
sy2 = sy2->clone;
|
|
}
|
|
/* find if defined on another section */
|
|
if (!def)
|
|
{
|
|
sy2 = sy;
|
|
/*fprintf(stderr,"%s of %s: look on the program\n",sy1->name,(sy1->parent)?sy1->parent->name:NULL); */
|
|
while (sy2)
|
|
{
|
|
/*fprintf(stderr,"%s of %s: compare with %s of %s\n",*/
|
|
/* sy1->name,(sy1->parent)?sy1->parent->name:NULL, */
|
|
/* sy2->name,(sy2->parent)?sy2->parent->name:NULL); */
|
|
|
|
/* look for it on another section or look if it is a
|
|
section (not a paragraph) */
|
|
if ((sy2->defined == 1 && sy2->parent
|
|
!= sy1->parent) || (sy2->defined == 1
|
|
&& sy2->parent == NULL && sy2->parent
|
|
== NULL))
|
|
{
|
|
/* If we have found it,
|
|
it needs a cast or the cast is incorrect */
|
|
if (def)
|
|
{
|
|
yyerror("procedure name not unique: %s",
|
|
sy1->name);
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, ".LB_%s = ", label_name(sy1));
|
|
fprintf(o_src, ".LB_%s\n", label_name(sy2));
|
|
fprintf(o_src, ".LE_%s = ", label_name(sy1));
|
|
fprintf(o_src, ".LE_%s\n", label_name(sy2));
|
|
def++;
|
|
}
|
|
/*break;*/
|
|
}
|
|
sy2 = sy2->clone;
|
|
} /* while sy2 */
|
|
} /* if(!def) */
|
|
if (!def)
|
|
{ /* really not defined, print an error */
|
|
yyerror("undefined procedure: %s", sy1->name);
|
|
|
|
}
|
|
|
|
} /* if (sy1->defined == 2) */
|
|
sy1 = sy1->clone;
|
|
} /* while (sy1) */
|
|
} /* for */
|
|
} /* for */
|
|
fprintf(o_src, "# finish resolving paragraphs/sections labels\n");
|
|
}
|
|
|
|
void open_section(struct sym *sect)
|
|
{
|
|
sect->type = 'S';
|
|
fprintf(o_src, ".LB_%s:\n", label_name(sect));
|
|
/* fprintf(o_src,".LB_%s:\n",sect->name); */
|
|
curr_section = sect;
|
|
}
|
|
|
|
void close_section(void)
|
|
{
|
|
close_paragr();
|
|
if (curr_section)
|
|
{
|
|
fprintf(o_src, ".LE_%s:\n", label_name(curr_section));
|
|
/* fprintf(o_src,".LE_%s:\n",curr_section->name); */
|
|
gen_exit(0);
|
|
}
|
|
}
|
|
|
|
char * label_name(struct sym *lab)
|
|
{
|
|
if (lab->parent)
|
|
{
|
|
sprintf(name_buf, "%s__%s_%d", lab->name, lab->parent->name,
|
|
pgm_segment);
|
|
chg_underline(name_buf);
|
|
/*fprintf(stderr,"# label_name: %s\n",name_buf);*/
|
|
return name_buf;
|
|
}
|
|
sprintf(name_buf, "%s_%d", lab->name, pgm_segment);
|
|
chg_underline(name_buf);
|
|
/*fprintf(stderr,"# label_name: %s\n",name_buf);*/
|
|
return name_buf;
|
|
}
|
|
|
|
void close_paragr(void)
|
|
{
|
|
if (curr_paragr)
|
|
{
|
|
fprintf(o_src, ".LE_%s:\n", label_name(curr_paragr));
|
|
/*fprintf(o_src,".stabn\t192,0,0,.LB_%s-main\n",
|
|
label_name( curr_paragr ));
|
|
#if !defined(__WINDOWS__)
|
|
fprintf(o_src,".stabn\t224,0,0,.LE_%s-main\n",
|
|
#else
|
|
fprintf(o_src,".stabn\t224,0,0,.LE_%s-_main\n",
|
|
#endif
|
|
label_name( curr_paragr ));*/
|
|
gen_exit(0);
|
|
curr_paragr = NULL;
|
|
}
|
|
}
|
|
|
|
void open_paragr(struct sym *paragr)
|
|
{
|
|
paragr->type = 'P';
|
|
curr_paragr = paragr;
|
|
fprintf(o_src, ".LB_%s:\n", label_name(paragr));
|
|
}
|
|
|
|
void gen_stoprun(void)
|
|
{
|
|
|
|
if ((main_flag == 1) && (main_entry_flag == FALSE))
|
|
{
|
|
strcpy(main_entry_buf, pgm_label);
|
|
main_entry_flag = TRUE;
|
|
}
|
|
|
|
fprintf(o_src, "\tleal\t.Lend_pgm_%s, %%eax\n", pgm_label);
|
|
fprintf(o_src, "\tpushl\t%%eax\n");
|
|
fprintf(o_src, "\tjmp\t.Lend_pgm_%s\n", pgm_label);
|
|
}
|
|
|
|
void gen_exit(int code)
|
|
{
|
|
int l1, l2;
|
|
struct list *list;
|
|
struct sym *f;
|
|
|
|
if (code)
|
|
{
|
|
if (initial_flag)
|
|
{
|
|
/* ensure all files are closed and initialized */
|
|
for (list = files_list; list != NULL; list = list->next)
|
|
{
|
|
f = (struct sym *) list->var;
|
|
gen_save_filevar(f, NULL);
|
|
asm_call("tcob_file_init");
|
|
}
|
|
}
|
|
|
|
/* fprintf(o_src,"\tmovl\t-%d(%%ebp), %%ebx\n",stack_offset - 16); */
|
|
fprintf(o_src, "\tmovl\t-%d(%%ebp), %%ebx\n", stack_offset - 24);
|
|
fprintf(o_src, "\tmov\t%%ebp,%%esp\n");
|
|
fprintf(o_src, "\tpop\t%%ebp\n");
|
|
fprintf(o_src, "\tret\n");
|
|
/*
|
|
fprintf(o_src,"\tleal\t.Lend_pgm_%s, %%eax\n",pgm_label);
|
|
fprintf(o_src,"\tpushl\t%%eax\n");
|
|
fprintf(o_src,"\tjmp\t.Lend_pgm_%s\n",pgm_label);
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
/*fprintf(o_src,"\tleal\t.LE_%s, %%eax\n",label_name(curr_paragr));*/
|
|
/*push_eax();*/
|
|
/*asm_call("exit_paragraph");*/
|
|
l1 = loc_label++;
|
|
l2 = loc_label++;
|
|
if (curr_paragr != NULL)
|
|
{
|
|
fprintf(o_src, "\tleal\t.LE_%s, %%eax\n", label_name(curr_paragr));
|
|
}
|
|
else
|
|
{
|
|
fprintf(o_src, "\tleal\t.LE_%s, %%eax\n", label_name(curr_section));
|
|
}
|
|
fprintf(o_src, "\tcmpl\t4(%%esp), %%eax\n");
|
|
fprintf(o_src, "\tjb\t\t.L%d\n", l1);
|
|
fprintf(o_src, "\tcmpl\t0(%%esp), %%eax\n");
|
|
fprintf(o_src, "\tjb\t\t.L%d\n", l2);
|
|
fprintf(o_src, ".L%d:\n", l1);
|
|
fprintf(o_src, "\taddl\t$8,%%esp\n");
|
|
inner_stack_size = 0;
|
|
fprintf(o_src, "\tret\n");
|
|
fprintf(o_src, ".L%d:\n", l2);
|
|
/*
|
|
fprintf(o_src,"\tleal\t.Lend_pgm_%s, %%eax\n",pgm_label);
|
|
fprintf(o_src,"\tpushl\t%%eax\n");
|
|
fprintf(o_src,"\tjmp\t.Lend_pgm_%s\n",pgm_label);
|
|
*/
|
|
}
|
|
}
|
|
|
|
void gen_condition(struct sym *sy)
|
|
{
|
|
struct vrange *vr;
|
|
struct vref *ref;
|
|
struct sym *sy1 = sy;
|
|
/*fprintf(o_src,"# 88 condition (top): (%s , %s)\n",
|
|
sy->value->name,sy->value2->name);*/
|
|
/* is this an indexed condition ? */
|
|
if (sy->litflag == 2)
|
|
{
|
|
sy1 = (struct sym *) ((struct vref *) sy)->sym;
|
|
}
|
|
gen_loadvar((struct sym *) NULL);
|
|
gen_loadvar((struct sym *) sy1->value2);
|
|
gen_loadvar((struct sym *) sy1->value);
|
|
vr = sy1->refmod_redef.vr;
|
|
while (vr)
|
|
{
|
|
/*fprintf(o_src,"# 88 condition: (%s , %s)\n",
|
|
vr->value->name,vr->value2->name);*/
|
|
gen_loadvar((struct sym *) vr->value2);
|
|
gen_loadvar((struct sym *) vr->value);
|
|
vr = vr->next;
|
|
}
|
|
if (sy->litflag == 2)
|
|
{
|
|
/* alloc a tmp node for condition parent
|
|
so gen_loadvar will be happy */
|
|
ref = malloc(sizeof(struct vref));
|
|
ref->litflag = 2;
|
|
ref->sym = sy1->parent;
|
|
ref->next = ((struct vref *) sy)->next;
|
|
gen_loadvar((struct sym *) ref);
|
|
free(ref);
|
|
ref = NULL;
|
|
}
|
|
else
|
|
{
|
|
gen_loadvar(sy->parent);
|
|
}
|
|
asm_call("tcob_check_condition");
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n");
|
|
}
|
|
|
|
/* compare for already stacked expressions */
|
|
void gen_compare_exp(int value)
|
|
{
|
|
stackframe_cnt += 16; /* must pop everything after comparing */
|
|
asm_call("tcob_compare_doubles");
|
|
switch (value)
|
|
{
|
|
case 0:
|
|
fprintf(o_src, "\txor\t%%eax,%%eax\n\tinc\t%%eax\n"); /* false */
|
|
break;
|
|
case 1:
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n"); /* equal */
|
|
break;
|
|
case 2:
|
|
fprintf(o_src, "\tinc\t%%eax\n"); /* less */
|
|
break;
|
|
case 3:
|
|
fprintf(o_src, "\tdec\t%%eax\n"); /* less or equal */
|
|
gen_not();
|
|
break;
|
|
case 4:
|
|
fprintf(o_src, "\tdec\t%%eax\n"); /* greater */
|
|
break;
|
|
case 5:
|
|
fprintf(o_src, "\tinc\t%%eax\n"); /* greater or equal */
|
|
gen_not();
|
|
break;
|
|
case 6:
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n"); /* not equal */
|
|
gen_not();
|
|
break;
|
|
case 7:
|
|
fprintf(o_src, "\txor\t%%eax,%%eax\n"); /* true */
|
|
break;
|
|
}
|
|
}
|
|
|
|
void gen_compare(struct sym *s1, int value, struct sym *s2)
|
|
{
|
|
/* if any of sy1 or sy2 is an expression, we must
|
|
compare full expressions */
|
|
if ((s1->litflag == 5) || (s2->litflag == 5))
|
|
{
|
|
push_expr(s2);
|
|
push_expr(s1);
|
|
gen_compare_exp(value);
|
|
}
|
|
else
|
|
{
|
|
gen_loadvar(s2);
|
|
gen_loadvar(s1);
|
|
asm_call("tcob_compare");
|
|
switch (value)
|
|
{
|
|
case 0:
|
|
fprintf(o_src, "\txor\t%%eax,%%eax\n\tinc\t%%eax\n"); /* false */
|
|
break;
|
|
case 1:
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n"); /* equal */
|
|
break;
|
|
case 2:
|
|
fprintf(o_src, "\tinc\t%%eax\n"); /* less */
|
|
break;
|
|
case 3:
|
|
fprintf(o_src, "\tdec\t%%eax\n"); /* less or equal */
|
|
gen_not();
|
|
break;
|
|
case 4:
|
|
fprintf(o_src, "\tdec\t%%eax\n"); /* greater */
|
|
break;
|
|
case 5:
|
|
fprintf(o_src, "\tinc\t%%eax\n"); /* greater or equal */
|
|
gen_not();
|
|
break;
|
|
case 6:
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n"); /* not equal */
|
|
gen_not();
|
|
break;
|
|
case 7:
|
|
fprintf(o_src, "\txor\t%%eax,%%eax\n"); /* true */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int push_subexpr(struct sym *sy)
|
|
{
|
|
if (sy == NULL)
|
|
return 0;
|
|
/* generate code to compute expr */
|
|
if (sy->litflag == 5)
|
|
{
|
|
push_subexpr((struct sym *) ((struct expr *) sy)->left);
|
|
push_subexpr((struct sym *) ((struct expr *) sy)->right);
|
|
switch (((struct expr *) sy)->op)
|
|
{
|
|
case '+':
|
|
add_expr();
|
|
break;
|
|
case '-':
|
|
subtract_expr();
|
|
break;
|
|
case '*':
|
|
multiply_expr();
|
|
break;
|
|
case '/':
|
|
divide_expr();
|
|
break;
|
|
case '^':
|
|
pow_expr();
|
|
break;
|
|
default:
|
|
yyerror("unknown expression operator");
|
|
}
|
|
}
|
|
/* sy is really a symbol, not expr */
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# push_subexpr: %s\n",sy->name);
|
|
#endif
|
|
if (sy)
|
|
{ /*only if not yet pushed*/
|
|
if (is_numeric_sy(sy))
|
|
{
|
|
fprintf(o_src, "\tsubl\t$%d, %%esp\n", sizeof(double));
|
|
fprintf(o_src, "\tleal\t0(%%esp),%%eax\n");
|
|
push_eax();
|
|
gen_loadvar(sy);
|
|
asm_call("tcob_fldtod");
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void add_expr(void)
|
|
{
|
|
fprintf(o_src, "\tleal\t8(%%esp),%%eax\n");
|
|
push_eax();
|
|
asm_call("tcob_add_double");
|
|
fprintf(o_src, "\taddl\t$8, %%esp\n");
|
|
}
|
|
|
|
void subtract_expr(void)
|
|
{
|
|
fprintf(o_src, "\tleal\t8(%%esp),%%eax\n");
|
|
push_eax();
|
|
asm_call("tcob_subtract_double");
|
|
fprintf(o_src, "\taddl\t$8, %%esp\n");
|
|
}
|
|
|
|
void multiply_expr(void)
|
|
{
|
|
fprintf(o_src, "\tleal\t8(%%esp),%%eax\n");
|
|
push_eax();
|
|
asm_call("tcob_multiply_double");
|
|
fprintf(o_src, "\taddl\t$8, %%esp\n");
|
|
}
|
|
|
|
void divide_expr(void)
|
|
{
|
|
fprintf(o_src, "\tleal\t8(%%esp),%%eax\n");
|
|
push_eax();
|
|
asm_call("tcob_divide_double");
|
|
fprintf(o_src, "\taddl\t$8, %%esp\n");
|
|
}
|
|
|
|
void pow_expr(void)
|
|
{
|
|
fprintf(o_src, "\tleal\t8(%%esp),%%eax\n");
|
|
push_eax();
|
|
asm_call("tcob_pow_double");
|
|
fprintf(o_src, "\taddl\t$8, %%esp\n");
|
|
}
|
|
|
|
void gen_save_filevar(struct sym *f, struct sym *buf)
|
|
{
|
|
|
|
if (!(f->recordsym))
|
|
{
|
|
yyerror("No FD for file e %s", f->name);
|
|
return;
|
|
}
|
|
|
|
if (buf != NULL)
|
|
{
|
|
gen_loadloc(buf);
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# File '%s' Record Description Stack Location\n",f->name);
|
|
#endif
|
|
|
|
/* fprintf(o_src,"\tleal\t-u(%%ebp), %%eax\n",f->record); */
|
|
fprintf(o_src, "\tmovl\t%s, %%eax\n", memref(f->recordsym));
|
|
push_eax();
|
|
}
|
|
if (f->type == 'K')
|
|
fprintf(o_src, "\tmovl\t$_%s, %%eax\n", f->name);
|
|
else
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# File name '%s', Record name '%s'\n",f->name, f->recordsym->name);
|
|
#endif
|
|
fprintf(o_src, "\tmovl\t$s_base%d+%u, %%eax\n", pgm_segment,
|
|
f->location);
|
|
push_eax();
|
|
}
|
|
|
|
void gen_save_filedesc(struct sym *f)
|
|
{
|
|
if (f->type == 'K')
|
|
fprintf(o_src, "\tmovl\t$_%s, %%eax\n", f->name);
|
|
else
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"# File name '%s', Record name '%s'\n",f->name, f->recordsym->name);
|
|
#endif
|
|
fprintf(o_src, "\tmovl\t$s_base%d+%u, %%eax\n", pgm_segment,
|
|
f->location);
|
|
push_eax();
|
|
}
|
|
|
|
/*static void gen_prtvar( struct sym *r, struct sym *buf ) {
|
|
struct sym *f;
|
|
f=r->ix_desc;
|
|
if (buf!=NULL)
|
|
gen_loadloc( buf );
|
|
fprintf(o_src,"\tleal\t-%d(%%ebp), %%eax\n",f->record);
|
|
push_eax();
|
|
if (buf != NULL)
|
|
fprintf(o_src,"\tmovl\t$%d, %%eax\n",buf->len);
|
|
else
|
|
fprintf(o_src,"\tmovl\t$%d, %%eax\n",r->len);
|
|
push_eax();
|
|
}*/
|
|
|
|
void gen_save_sort_fields(struct sym *f, struct sym *buf)
|
|
{
|
|
struct sym *datafld;
|
|
if (f == NULL)
|
|
return;
|
|
datafld = (struct sym *) f->sort_data;
|
|
while (datafld != NULL)
|
|
{
|
|
gen_loadloc(datafld);
|
|
datafld = (struct sym *) (datafld->sort_data);
|
|
}
|
|
fprintf(o_src, "\tmovl\t$c_base%d+%u, %%eax\n", pgm_segment, f->descriptor);
|
|
push_eax();
|
|
gen_save_filevar(f, buf);
|
|
/* returns number of stack levels used in storing fields */
|
|
}
|
|
|
|
void dump_alternate_keys(struct sym *r, struct alternate_list *alt)
|
|
{
|
|
struct alternate_list *tmp;
|
|
struct sym *key;
|
|
while (alt)
|
|
{
|
|
key = alt->key;
|
|
fprintf(o_src, "# alternate key %s\n", key->name);
|
|
fprintf(o_src,
|
|
/* "\t.word\t%d\n\t.long\tc_base+%d,0\n\t.word\t%d\n", */
|
|
"\t.word\t%d\n\t.long\tc_base%d+%d\n\t.word\t%d\n\t.long\t0\n",
|
|
/*r->location - key->location,*/
|
|
key->location - r->location, pgm_segment, key->descriptor,
|
|
alt->duplicates);
|
|
tmp = alt;
|
|
alt = alt->next;
|
|
free(tmp);
|
|
tmp = NULL;
|
|
}
|
|
fprintf(o_src, "# end of alternate keys\n.word\t-1\n");
|
|
}
|
|
|
|
/*
|
|
** dump all file descriptors in file_list
|
|
*/
|
|
void dump_fdesc()
|
|
{
|
|
|
|
struct sym *f;
|
|
struct sym *r;
|
|
struct list *list/*,*visited*/;
|
|
unsigned char fflags;
|
|
|
|
/*fprintf(o_src,".data\n\t.align 4\n");*/
|
|
fprintf(o_src, "s_base%d:\t.long\t0\n", pgm_segment);
|
|
if (files_list != NULL)
|
|
{
|
|
/* fprintf(o_src,"s_base:\n"); */
|
|
}
|
|
for (list = files_list; list != NULL; list = list->next)
|
|
{
|
|
f = (struct sym *) list->var;
|
|
r = f->recordsym;
|
|
#ifdef DEBUG_COMPILER
|
|
/* fprintf(o_src,"# FILE DESCRIPTOR, File: %s, Record: %s, Data Loc: %d(%x)\n",
|
|
f->name,r->name,global_offset); */
|
|
fprintf(o_src,"# FILE DESCRIPTOR, File: %s, Record: %s, Data Loc: %d(hex: %x)\n",
|
|
f->name,r->name,f->location,f->location);
|
|
fprintf(o_src,"# FILE DESCRIPTOR2, opt: %x\n",
|
|
f->flags.optional);
|
|
#endif
|
|
if (f->filenamevar == NULL)
|
|
{
|
|
yyerror("No file name assigned to %s.", f->name);
|
|
continue;
|
|
}
|
|
if (f->type == 'K')
|
|
{
|
|
fprintf(o_src, "\t.extern\t_%s:far\n", f->name);
|
|
continue;
|
|
}
|
|
if (f->type == 'J')
|
|
{
|
|
fprintf(o_src, "\tpublic\t_%s\n", f->name);
|
|
fprintf(o_src, "_%s\tlabel\tbyte\n", f->name);
|
|
}
|
|
fflags = f->flags.optional;
|
|
fprintf(o_src, "\t.byte\t%u\n", RTL_FILE_VERSION);
|
|
fprintf(o_src, "\t.long\tc_base%d+%u\n", pgm_segment,
|
|
f->filenamevar->descriptor);
|
|
fprintf(o_src, "\t.word\t%u\n", r->len);
|
|
fprintf(o_src, "\t.byte\t%d,%d\n", f->organization, f->access_mode);
|
|
fprintf(o_src, "\t.long\t0\n"); /* open_mode */
|
|
fprintf(o_src, "\t.space\t2\n"); /* file_status */
|
|
fprintf(o_src, "\t.space\t2\n"); /* file_status (future ptr) */
|
|
fprintf(o_src, "\t.long\t0\n"); /* struct DBT (libdb) */
|
|
fprintf(o_src, "\t.long\t0\n"); /* start_record */
|
|
fprintf(o_src, "\t.byte\t%x\n", fflags); /* flags */
|
|
if (f->organization == 1)
|
|
{ /* indexed file */
|
|
if (f->ix_desc)
|
|
{
|
|
fprintf(o_src, "\t.word\t%d\n\t.long\tc_base%d+%d\n",
|
|
f->ix_desc->location - r->location, pgm_segment,
|
|
f->ix_desc->descriptor);
|
|
}
|
|
else
|
|
{
|
|
/* no key field was given for this file */
|
|
fprintf(o_src, "\t.word\t0\n\t.long\t0\n");
|
|
}
|
|
fprintf(o_src, "\t.long\t0\n"); /* struct altkey_desc *key_in_use */
|
|
dump_alternate_keys(r, (struct alternate_list *) f->alternate);
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned long int emt_call(struct lit *v, int stack_size, int exceplabel,
|
|
int notexceplabel, struct sym *ret)
|
|
{
|
|
struct parm_list *list, *tmp;
|
|
struct sym *cp;
|
|
struct lit *lp;
|
|
int len, totlen = 0, err = 0;
|
|
int saved_stack_offset = stack_offset;
|
|
int stack_save;
|
|
int endlabel;
|
|
char callname[128];
|
|
char *sp = '\0';
|
|
|
|
/******** prepare all parameters which are passed by content ********/
|
|
for (list = parameter_list; list != NULL; list = list->next)
|
|
{
|
|
cp = (struct sym *) list->var;
|
|
if (cp->litflag != 1)
|
|
{
|
|
if (cp->call_mode == CM_CONT)
|
|
{
|
|
len = symlen(cp); /* should we round to 4? */
|
|
totlen += len;
|
|
list->sec_no = SEC_STACK;
|
|
list->location = stack_offset + len;
|
|
stack_offset += len;
|
|
fprintf(o_src, "\tsubl\t$%d, %%esp\n", len);
|
|
push_immed(len); /* length */
|
|
gen_loadloc(cp); /* src address */
|
|
fprintf(o_src, "\tleal\t-%d(%%ebp), %%eax\n", list->location);
|
|
push_eax(); /* dest address ie on stack */
|
|
asm_call("memcpy");
|
|
}
|
|
}
|
|
}
|
|
/******** get the parameters from the parameter list ********/
|
|
for (list = parameter_list; list != NULL;)
|
|
{
|
|
cp = (struct sym *) list->var;
|
|
if (cp->litflag == 1)
|
|
{
|
|
lp = (struct lit*) cp;
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src, "#call %s by %d\n", lp->name,lp->call_mode);
|
|
#endif
|
|
if (lp->call_mode == CM_REF)
|
|
gen_loadloc((struct sym *) list->var);
|
|
else if (lp->call_mode == CM_VAL)
|
|
{
|
|
value_to_eax(cp);
|
|
if (symlen(cp) > 4)
|
|
push_edx();
|
|
push_eax();
|
|
}
|
|
/* else
|
|
gen_loadvar((struct sym *)list->var)*/;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src, "#call %s by %d\n", cp->name,cp->call_mode);
|
|
#endif
|
|
if (cp->call_mode == CM_REF)
|
|
gen_loadloc((struct sym *) list->var);
|
|
else if (cp->call_mode == CM_VAL)
|
|
{
|
|
gen_pushval((struct sym *) list->var);
|
|
}
|
|
else if (cp->call_mode == CM_CONT)
|
|
{
|
|
fprintf(o_src, "\tleal\t-%d(%%ebp), %%eax\n", list->location);
|
|
push_eax();
|
|
}
|
|
else
|
|
gen_loadvar((struct sym *) list->var);
|
|
}
|
|
tmp = list;
|
|
list = list->next;
|
|
free(tmp);
|
|
tmp = NULL;
|
|
}
|
|
parameter_list = NULL;
|
|
if ((v->litflag == 1) && (!HTG_all_calls_dynamic))
|
|
{
|
|
/* call literal (static) routine */
|
|
|
|
/*
|
|
check for valid characters in program name
|
|
*/
|
|
sp = v->name;
|
|
if (!(isalpha(*sp) || (*sp == '_')))
|
|
{
|
|
err++;
|
|
yyerror("Invalid character '%c' in program name '%s'", *sp, v->name);
|
|
}
|
|
sp++;
|
|
while (*sp != '\0')
|
|
{
|
|
if (!(isalnum(*sp) || (*sp == '$') || (*sp == '.') || (*sp == '_')))
|
|
{
|
|
err++;
|
|
yyerror("Invalid character '%c' in program name '%s'", *sp,
|
|
v->name);
|
|
}
|
|
sp++;
|
|
}
|
|
if (err != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* use standard C call convention */
|
|
if (curr_call_convention == 0)
|
|
asm_call(v->name);
|
|
else
|
|
{
|
|
/*
|
|
When the STDCALL (WINAPI) call convention is used
|
|
stack pointer is cleared by called function
|
|
*/
|
|
stack_save = stackframe_cnt;
|
|
/* set the Win32 (MinGW) naming convention (function_name@arg_length) */
|
|
sprintf(callname, "%s@%d", v->name, stack_save);
|
|
asm_call(callname);
|
|
/* reset the stack pointer */
|
|
fprintf(o_src, "\tsubl\t$%d, %%esp\n", stack_save);
|
|
}
|
|
endlabel = 0;
|
|
gen_store_fnres(ret);
|
|
gen_enter_runelement(RUN_ELEMENT_RETURN);
|
|
}
|
|
else
|
|
{
|
|
#if defined(__WINDOWS__)
|
|
/*
|
|
// this code execute a workaround on the situation of
|
|
// calling "system" on a program compiled using
|
|
// dinamic calls... "cblsys" is found on cobroutines...
|
|
// Nilo, 2007, april 17
|
|
*/
|
|
if ( !strcmp(v->name,"system") )
|
|
{
|
|
strcpy(v->name,"cblsys");
|
|
}
|
|
#endif
|
|
/* call dynamic routine (call by name) */
|
|
stack_save = stackframe_cnt;
|
|
stackframe_cnt = 0;
|
|
|
|
if (curr_call_convention == 0)
|
|
fprintf(o_src, "\tpushl\t$0\n");
|
|
else
|
|
{
|
|
fprintf(o_src, "\tpushl\t$%d\n", stack_save + 1);
|
|
}
|
|
stackframe_cnt = stackframe_cnt + 4;
|
|
|
|
gen_loadvar((struct sym *) v);
|
|
asm_call("tcob_resolve_subr");
|
|
|
|
/*
|
|
PROBLEM CODE - FIX ME ? ---------------------
|
|
|
|
With the 'static call' the call paramaters are
|
|
pushed on to the stack, then the CALL function
|
|
is called. No problem here.
|
|
|
|
With the 'dynamic call' the call paramaters are
|
|
pushed on to the stack, then the 'tcob_resolve_subr'
|
|
paramaters are pushed on to the stack, then the
|
|
'tcob_resolve_subr' function is called.
|
|
If the 'tcob_resolve_subr' function is true then
|
|
the pointer to the function is called. If false
|
|
then the CALL is by-passed (jump).
|
|
|
|
Problem:
|
|
When the CALL is by-passed the stack pointer
|
|
is not reset.
|
|
|
|
Temporary fix:
|
|
Reset the stack pointer before the compare and jump.
|
|
Then reset the stack pointer back before the function
|
|
call.
|
|
*/
|
|
stackframe_cnt = stack_save;
|
|
|
|
/* Reset the stack pointer in case 'tcob_resolve_subr' fails */
|
|
fprintf(o_src, "\taddl\t$%d, %%esp\n", stack_save);
|
|
|
|
fprintf(o_src, "\tand\t%%eax,%%eax\n");
|
|
fprintf(o_src, "\tjz\t.L%d\n", exceplabel);
|
|
|
|
/* Reset the stack pointer when 'tcob_resolve_subr' succeeds */
|
|
fprintf(o_src, "\tsubl\t$%d, %%esp\n", stack_save);
|
|
fprintf(o_src, "\tcall\t*%%eax\n");
|
|
|
|
if (curr_call_convention == 0)
|
|
cleanup_rt_stack();
|
|
|
|
endlabel = loc_label++;
|
|
gen_store_fnres(ret);
|
|
gen_enter_runelement(RUN_ELEMENT_RETURN);
|
|
fprintf(o_src, "\tjmp\t.L%d\n", notexceplabel);
|
|
|
|
HTG_prg_uses_dcall = 1; /* mark we use dynamic calls for the linker step */
|
|
}
|
|
/*fprintf(o_src,"\taddl\t$%d, %%esp\n",stack_size*2);*/
|
|
if (totlen != 0)
|
|
fprintf(o_src, "\taddl\t$%d, %%esp\n", totlen);
|
|
stack_offset = saved_stack_offset;
|
|
return endlabel;
|
|
}
|
|
|
|
unsigned long int emt_call_loadlib(struct lit *v)
|
|
{
|
|
|
|
gen_loadvar((struct sym *) v);
|
|
asm_call("tcob_call_loadlib");
|
|
return 0;
|
|
}
|
|
|
|
int begin_on_except()
|
|
{
|
|
int lab = loc_label++;
|
|
fprintf(o_src, ".L%d:\t# begin_on_except\n", lab);
|
|
stabs_line();
|
|
return lab;
|
|
}
|
|
|
|
void check_call_except(int excep, int notexcep, int exceplabel,
|
|
int notexceplabel, int endlabel)
|
|
{
|
|
|
|
/* generate code only if was "call <identifier>" */
|
|
if (endlabel != 0)
|
|
{
|
|
fprintf(o_src, ".L%d:\t# exceplabel\n", exceplabel);
|
|
if (excep)
|
|
{
|
|
fprintf(o_src, "\tjmp\t.L%d\n", excep);
|
|
}
|
|
/* if no exception phrase was given */
|
|
if (excep == 0)
|
|
{
|
|
/* fprintf(o_src,"\tcall\ttcob_resolve_subr_error\n"); */
|
|
asm_call("tcob_resolve_subr_error");
|
|
fprintf(o_src, "\tjmp\t.L%d\n", endlabel);
|
|
}
|
|
fprintf(o_src, ".L%d:\t# notexceplabel\n", notexceplabel);
|
|
if (notexcep)
|
|
{
|
|
fprintf(o_src, "\tjmp\t.L%d\n", notexcep);
|
|
}
|
|
fprintf(o_src, ".L%d:\t# endlabel\n", endlabel);
|
|
}
|
|
}
|
|
|
|
/* Generates code for inline intrinsic functions,
|
|
returns a field containing the return value of the intrinsic functions */
|
|
struct sym *gen_inline_intrinsic(struct sym *v)
|
|
{
|
|
struct parm_list *list, *tmp;
|
|
struct sym *temporary;
|
|
static struct lit *when_compiled = NULL;
|
|
struct sym *cp = NULL;
|
|
if (parameter_list)
|
|
cp = (struct sym *) parameter_list->var;
|
|
|
|
if (strcasecmp("LENGTH", v->name) == 0)
|
|
{
|
|
temporary = define_temp_field(DTYPE_BININT, sizeof(int));
|
|
fprintf(o_src, "\tmovl\t$%d, %s #%s\n", set_field_length(cp, 1),
|
|
memrefat(temporary), cp->name);
|
|
}
|
|
else if (strcasecmp("ORD", v->name) == 0)
|
|
{
|
|
temporary = define_temp_field(DTYPE_BININT, sizeof(int));
|
|
fprintf(o_src, "\tmovsbl\t%s, %%eax\n", memrefat(cp));
|
|
fprintf(o_src, "\taddl\t$1, %%eax\n"/*, memrefat(cp),
|
|
memrefat(temporary), cp->name*/);
|
|
fprintf(o_src, "\tmovl\t%%eax, %s\n", memrefat(temporary));
|
|
}
|
|
else if (strcasecmp("CHAR", v->name) == 0)
|
|
{
|
|
temporary = define_temp_field(DTYPE_ALPHANUMERIC, 1);
|
|
gen_loadval(cp);
|
|
fprintf(o_src, "\tsubl\t$1, %%eax\n" /*,memrefat(cp),
|
|
memrefat(temporary), cp->name*/);
|
|
fprintf(o_src, "\tmovb\t%%al, %s\n", memrefat(temporary));
|
|
}
|
|
else if (strcasecmp("WHEN-COMPILED", v->name) == 0)
|
|
{
|
|
if (when_compiled == NULL)
|
|
{ /* If first time, create the literal */
|
|
char now_str[22];
|
|
time_t now;
|
|
now = time(NULL);
|
|
/* Needs fix to fill positions 15 to 21 */
|
|
/* (milliseconds and diff between local and Univeral Time) */
|
|
strftime(now_str, 22, "%Y%m%d%H%M%S0000000", localtime(&now));
|
|
when_compiled = install_lit(now_str, 22, 0);
|
|
save_literal(when_compiled, DTYPE_DISPLAY);
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src,"#Creating compile time literal:%s\n",now_str);
|
|
#endif
|
|
}
|
|
temporary = (struct sym *) when_compiled;
|
|
}
|
|
else
|
|
{
|
|
yyerror("inline Intrinsic function type not yet implemented");
|
|
}
|
|
|
|
/* Free parameter list */
|
|
for (list = parameter_list; list != NULL;)
|
|
{
|
|
tmp = list;
|
|
list = list->next;
|
|
free(tmp);
|
|
tmp = NULL;
|
|
}
|
|
parameter_list = NULL;
|
|
return temporary;
|
|
}
|
|
|
|
/*
|
|
* Makes a call to an intrinsic function using the parameter list.
|
|
* Returns a pointer to a temporaty field that contains the value returned by
|
|
* the function.
|
|
*
|
|
* This function does not use anything platform dependent,
|
|
* and may be trasferred to htcobgen
|
|
*/
|
|
struct sym *gen_intrinsic_call(struct sym *v)
|
|
{
|
|
struct parm_list *list, *tmp;
|
|
struct sym *cp;
|
|
char intrinsic_name[50] = "tcob_intrinsic_";
|
|
unsigned short inp;
|
|
struct sym *temporary = NULL;
|
|
struct intrinsic_function *function = NULL;
|
|
|
|
/* fprintf(stderr,"in:%s\n",v->name); */
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src, "#call intrinsic %s \n", v->name);
|
|
#endif
|
|
/* Look for data types of intrinsic function */
|
|
function = lookup_intrinsic_function(v->name);
|
|
if (function == NULL)
|
|
{
|
|
yyerror("Intrinsic function type not recognized");
|
|
return NULL;
|
|
}
|
|
/* Define a temporaty field as needed */
|
|
switch (function->function_type)
|
|
{
|
|
case ITYPE_FLOAT:
|
|
temporary = define_temp_field(DTYPE_FLOAT, sizeof(double));
|
|
break;
|
|
case ITYPE_DATE: /* Date fields defined as PIC 9(8) */
|
|
temporary = define_temp_field(DTYPE_DISPLAY, 8);
|
|
break;
|
|
case ITYPE_INT:
|
|
temporary = define_temp_field(DTYPE_BININT, sizeof(int));
|
|
break;
|
|
case ITYPE_DATETIME:
|
|
temporary = define_temp_field(DTYPE_ALPHANUMERIC, 21);
|
|
break;
|
|
case ITYPE_JULIANDATE:
|
|
temporary = define_temp_field(DTYPE_DISPLAY, 7);
|
|
break;
|
|
case ITYPE_YEAR:
|
|
temporary = define_temp_field(DTYPE_DISPLAY, 4);
|
|
break;
|
|
case ITYPE_ALPHA:
|
|
/* Maximmum length supported is 255 chars */
|
|
/* Is the maximum supported by define_temp_field */
|
|
temporary = define_temp_field(DTYPE_ALPHANUMERIC, 255);
|
|
break;
|
|
case ITYPE_INLINE:
|
|
return gen_inline_intrinsic(v);
|
|
break;
|
|
default:
|
|
yyerror("Intrinsic function type not recognized");
|
|
return NULL;
|
|
}
|
|
/* construct the routine name */
|
|
strcat(intrinsic_name, v->name);
|
|
/* Force to lowercase, change - to _ */
|
|
for (inp = 15; inp <= (strlen(v->name) + 15); inp++)
|
|
{
|
|
if (intrinsic_name[inp] >= 'A' && intrinsic_name[inp] <= 'Z')
|
|
intrinsic_name[inp] += 32;
|
|
if (intrinsic_name[inp] == '-')
|
|
intrinsic_name[inp] = '_';
|
|
}
|
|
/* First we push a NULL to mark end of parameters */
|
|
push_immed(0);
|
|
/******** get the parameters from the parameter list ********/
|
|
/* Intrinsics are always called by reference */
|
|
inp = 0; /* used to count number of args */
|
|
for (list = parameter_list; list != NULL;)
|
|
{
|
|
cp = (struct sym *) list->var;
|
|
#ifdef DEBUG_COMPILER
|
|
fprintf(o_src, "#call intrinsic parameter %s \n", cp->name);
|
|
#endif
|
|
gen_loadvar(cp);
|
|
tmp = list;
|
|
list = list->next;
|
|
free(tmp);
|
|
tmp = NULL;
|
|
inp++;
|
|
}
|
|
parameter_list = NULL;
|
|
/* check number of args */
|
|
if ((function->args != ANY_NUMBER) && (function->args != inp))
|
|
{
|
|
yyerror("Invalid number of args calling intrinsic %s", v->name);
|
|
}
|
|
|
|
/* push the destination field */
|
|
gen_loadvar(temporary);
|
|
asm_call(intrinsic_name);
|
|
/*gen_store_fnres(temporary);*/
|
|
|
|
return temporary;
|
|
}
|
|
|
|
/* end of HTCOBEMT.C */
|