⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gen.c

📁 一个c语言写做的编译器的源码
💻 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 + -