📄 gen.c
字号:
/*@A (C) 1992 Allen I. Holub */
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <search.h>
#include <tools/debug.h>
#include <tools/hash.h>
#include <tools/l.h>
#include <tools/compiler.h>
#include <tools/occs.h>
#include "symtab.h"
#include "value.h"
#include "proto.h"
PRIVATE int Trace = 0; /* Generate run-time trace if true. */
typedef enum request
{
t_assign_addr, t_assign_ind, t_call, t_endp, t_ext, t_goto, t_goto_int,
t_label, t_label_int, t_link, t_logical, t_logical_int, t_lrs, t_math,
t_math_int, t_pop, t_proc, t_push, t_ret, t_unlink
} request;
PRIVATE int cmp P((struct ltab *a,struct ltab *b));
PRIVATE void print_instruction P(( char *b, request t ));
/*----------------------------------------------------------------------*/
struct ltab
{
char *lexeme;
request token;
}
Ltab[] =
{
{"%=", t_math },
{"&=", t_math },
{"*=", t_math },
{"*=%s%d", t_math_int }, /* Multiply var by constant. */
{"+=", t_math },
{"+=%s%d", t_math_int },
{"-=", t_math },
{"-=%s%d", t_math_int },
{"/=", t_math },
{"/=%s%d", t_math_int },
{":", t_label },
{":%s%d", t_label_int },
{"<<=", t_math },
{"=", t_math },
{"=&", t_assign_addr }, /* Get effective address. */
{"=*%s%v", t_assign_ind }, /* Assign indirect. */
{"=-", t_math },
{">>=", t_math },
{">L=", t_lrs },
{"BIT", t_logical },
{"ENDP", t_endp },
{"EQ", t_logical },
{"EQ%s%d", t_logical_int },
{"GE", t_logical },
{"GT", t_logical },
{"LE", t_logical },
{"LT", t_logical },
{"NE", t_logical },
{"PROC", t_proc },
{"U_GE", t_logical },
{"U_GT", t_logical },
{"U_LE", t_logical },
{"U_LT", t_logical },
{"^=", t_math },
{"call", t_call },
{"ext_high", t_ext },
{"ext_low", t_ext },
{"ext_word", t_ext },
{"goto", t_goto },
{"goto%s%d", t_goto_int },
{"link", t_link },
{"pop", t_pop },
{"push", t_push },
{"ret", t_ret },
{"unlink", t_unlink },
{"|=", t_math }
};
#define NREQ ( sizeof(Ltab)/sizeof(*Ltab) ) /* Table size (in elements). */
char Comment_buf[132]; /* Remember comment text here. */
/*----------------------------------------------------------------------*/
ANSI( PUBLIC void gen_comment( char *format, ... ) )
KnR( PUBLIC void gen_comment( format ) )
KnR( char *format; )
{
/* Works like printf(), but the string is appended as a comment to the end
* of the command generated by the next gen() call. There's no array-size
* checking---be careful. The maximum generated string length is 132
* characters. Overwrite any comments already in the buffer.
*/
va_list args;
va_start ( args, format );
vsprintf ( Comment_buf, format, args );
va_end ( args );
}
/*----------------------------------------------------------------------
* Enable/disable the generation of run-time trace output.
*/
PUBLIC void enable_trace() { Trace=1; } /* Must call before parsing starts. */
PUBLIC void disable_trace(){ Trace=0; }
/*----------------------------------------------------------------------*/
PRIVATE int cmp( a, b ) /* Compare two lexeme fields of an ltab. */
struct ltab *a, *b;
{
return strcmp( a->lexeme, b->lexeme );
}
/*----------------------------------------------------------------------*/
ANSI( PUBLIC void gen( char *op, ... ) ) /* emit code */
KnR( PUBLIC void gen( op ) )
KnR( char *op; )
{
char *dst_str, *src_str, b[80];
int src_int;
value *src_val;
struct ltab *p, dummy;
request tok;
va_list args;
char *prefix = " " ;
int amt;
if( *op == '@' )
{
++op;
prefix = "*" ;
}
/* The following cast is really inexcusable, but Borland C++ requires it.
*/
dummy.lexeme = op;
if( !(p = (struct ltab *) bsearch(&dummy, Ltab, NREQ, sizeof(*Ltab),
BCC( (int _Cdecl(*) (const void _FAR *, const void _FAR *)) )
MSC( (int (__cdecl *)(const void *, const void *)) ) cmp)))
{
yyerror("INTERNAL gen: bad request <%s>, no code emitted.\n", op );
return;
}
va_start( args, op ); /* Get the arguments. */
dst_str = va_arg( args, char* );
switch( tok = p->token )
{
case t_math_int:
case t_logical_int:
case t_goto_int:
case t_label_int: src_int = va_arg( args, int ); break;
case t_assign_ind: src_val = va_arg( args, value* ); break;
default: src_str = va_arg( args, char* ); break;
}
va_end( args);
/* The following code just assembles the output string. It is printed with
* the print_instruction() call under the switch, which also takes care of
* inserting trace directives, inserting the proper indent, etc.
*/
switch( tok )
{
case t_call: sprintf(b," call(%s);", dst_str ); break;
case t_endp: sprintf(b," ENDP(%s)", dst_str, src_str ); break;
case t_ext: sprintf(b," %s(%s);", op, dst_str ); break;
case t_goto: sprintf(b," goto %s;", dst_str ); break;
case t_goto_int: sprintf(b," goto %s%d;", dst_str, src_int ); break;
case t_label: sprintf(b,"%s:", dst_str ); break;
case t_label_int: sprintf(b,"%s%d:", dst_str, src_int );
tok = t_label;
break;
case t_logical: sprintf(b," %s(%s,%s)", op, dst_str, src_str );
break;
case t_logical_int: sprintf(b," %2.2s(%s,%d)", op, dst_str, src_int );
tok = t_logical;
break;
case t_link: sprintf(b," link(%s+%s);", dst_str, src_str ); break;
case t_pop: sprintf(b," %-12s = pop(%s);",dst_str, src_str ); break;
case t_proc: sprintf(b," PROC(%s,%s)", dst_str, src_str ); break;
case t_push: sprintf(b," push(%s);", dst_str ); break;
case t_ret: sprintf(b," ret();" ); break;
case t_unlink: sprintf(b," unlink();" ); break;
case t_lrs: sprintf(b,"%slrs(%s,%s);", prefix, dst_str, src_str);
break;
case t_assign_addr: sprintf(b,"%s%-12s = &%s;", prefix, dst_str, src_str);
break;
case t_assign_ind:
if( src_val->name[0]=='&' )
sprintf(b,"%s%-12s = %s;",prefix, dst_str, src_val->name+1);
else
sprintf(b,"%s%-12s = *%s;",prefix, dst_str, src_val->name);
break;
case t_math: sprintf(b,"%s%-12s %s %s;", prefix, dst_str, op, src_str);
break;
case t_math_int:
if( *op != '*' && *op != '/' )
sprintf(b,"%s%-12s %2.2s %d;", prefix, dst_str, op, src_int);
else
{
switch( src_int )
{
case 1 : amt = 0; break;
case 2 : amt = 1; break;
case 4 : amt = 2; break;
case 8 : amt = 3; break;
case 16: amt = 4; break;
case 32: amt = 5; break;
case 64: amt = 6; break;
case 128: amt = 7; break;
case 256: amt = 8; break;
case 512: amt = 9; break;
case 1024: amt = 10; break;
case 2048: amt = 11; break;
case 4096: amt = 12; break;
default: amt = -1; break;
}
if( !amt )
sprintf(b, "/* %s%-12s %s 1; */", prefix, dst_str, op );
else if( amt < 0 )
sprintf(b, "%s%-12s %s %d;", prefix, dst_str, op, src_int);
else
sprintf(b, "%s%-12s %s %d;", prefix, dst_str,
(*op == '*') ? "<<=" : ">>=" , amt);
}
break;
default:
yyerror("INTERNAL, gen: bad token %s, no code emitted.\n", op );
break;
}
if( *Comment_buf ) /* Add optional comment at end of line. */
{
concat( sizeof(b), b, b, (tok == t_label ? "\t\t\t\t" : "\t"),
"/* ", Comment_buf, " */", NULL );
*Comment_buf = '\0';
}
print_instruction( b, tok ); /* Output the instruction. */
}
/*----------------------------------------------------------------------*/
PRIVATE void print_instruction( b, t )
char *b; /* Buffer containing the instruction. */
request t; /* Token representing instruction. */
{
/* Print the instruction and, if trace is enabled (Trace is true), print
* code to generate a run-time trace.
*/
extern FILE *yycodeout, *yybssout;
static int printed_defs = 0;
static int last_stmt_was_test;
if( Trace && !printed_defs )
{
printed_defs = 1;
fprintf( yybssout, "#define _P(s) printf( s )\n" );
fprintf( yybssout,
"#define _T() pm(),printf(\"------------------------------\\n\")");
fprintf( yybssout, "\n\n" );
}
if( !Trace ) /* just print the instruction */
{
yycode("%s%s%s\n", (t==t_label || t==t_endp || t==t_proc) ? "" : "\t",
( last_stmt_was_test ) ? " ": "" ,
b );
last_stmt_was_test = (t==t_logical);
}
else if( t == t_logical )
{
fprintf( yycodeout, "\t\t\t\t\t_P(\"%s\\n\");\n", b);
yycode("\t%s\t\t{\n", b); /*}*/
last_stmt_was_test = 1;
}
else
{
switch( t )
{
case t_label: yycode("%s", b);
fprintf( yycodeout, "\t\t\t\t\t_P(\"%s\\n\");", b);
break;
case t_proc: yycode("%s", b);
fprintf( yycodeout, "\t\t\t_P(\"%s\\n\");", b);
fprintf( yycodeout, "_T();" );
break;
case t_ret:
case t_endp: fprintf( yycodeout, "\t\t\t\t\t_P(\"%s\\n\");\n",b);
yycode("%s", b);
break;
default: fprintf( yycodeout, "\t\t\t\t\t_P(\"%s\\n\");\n",b);
yycode("\t%s%s", last_stmt_was_test ? " " : "", b);
fprintf( yycodeout, "\t\t\t_T();" );
}
if( last_stmt_was_test ) /* { */
{
putc( '}', yycodeout );
last_stmt_was_test = 0;
}
putc( '\n', yycodeout );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -