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

📄 asmcodegenerator.cpp

📁 C-编译器的设计文档与源代码下载,1. 具有比较友好的GUI界面(仿照了我自己正在用的emacs); 2. 语法支持比较全面(毕竟是C-
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// AsmCodeGenerator.cpp : implementation file
//

#include "stdafx.h"
#include "cminus.h"

#include "AsmCodeGenerator.h"

/*  *    CAsmCodeGenerator
    *    Construction & destruction
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.25             */

CAsmCodeGenerator::CAsmCodeGenerator( CString& str )
{
	m_pAnalyzer = new CAnalyzer( str );
	label		= 1;
}

CAsmCodeGenerator::~CAsmCodeGenerator()
{
}

/*  *    CAsmCodeGenerator
    *    Main routine, generating ASM Code
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.26             */

void CAsmCodeGenerator::GenerateAsmCode( LPCTSTR lpszPathName )
{
	m_pAnalyzer->TraceTypeCheck();
	if( bErrFlag ) {
		OutputPhaseMsg( "\r\nerrors occur, stop generating code!" );
		return;
	}
	ASSERT( m_pAnalyzer->m_pProgram != NULL );

	// create file
	CFileException e;
	if( !m_file.Open( lpszPathName, CFile::modeCreate | CFile::modeReadWrite, &e ) ) {
		OutputErrMsg( "failed to create file for code generation: %s", lpszPathName );
		return;
	}

	// generating p-code
	OutputPhaseMsg( "\r\ngenerating 80x86 asm code..." );
	genPreSeg();
	genCodeSeg();

	// close the file
	m_file.Close();
}

/*  *    CAsmCodeGenerator
    *    Help routines
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.25             */

// write comments to m_file, which must exist
void CAsmCodeGenerator::emitComment( char* format, ... )
{
	ASSERT( m_file.m_hFile != CFile::hFileNull );

	va_list params;
	static char buf[ 1024 ];
	buf[0] = ';';
	
	va_start( params, format );
	_vsnprintf( buf + 1, 1020, format, params );
	strcat( buf, "\r\n" );
	va_end( params );

	try {
		m_file.Write( buf, strlen(buf) );
	} catch( CFileException* ) {
		OutputErrMsg( "failed to write to file: %s", (LPCTSTR)m_file.GetFilePath() );
	}
}

// write label to m_file, which must exist
void CAsmCodeGenerator::emitLabel( char* format, ... )
{
	ASSERT( m_file.m_hFile != CFile::hFileNull );

	va_list params;
	static char buf[ 1024 ];

	va_start( params, format );
	_vsnprintf( buf, 1020, format, params );
	strcat( buf, "\r\n" );

	try {
		m_file.Write( buf, strlen(buf) );
	} catch( CFileException* ) {
		OutputErrMsg( "failed to write to file: %s", (LPCTSTR)m_file.GetFilePath() );
	}
}

// write codes to m_file, which must exist
void CAsmCodeGenerator::emitCode( char* format, ... )
{
	ASSERT( m_file.m_hFile != CFile::hFileNull );

	va_list params;
	static char buf[ 1024 ];
	buf[0] = '\t';
	
	va_start( params, format );
	_vsnprintf( buf + 1, 1020, format, params );
	strcat( buf, "\r\n" );
	va_end( params );

	try {
		m_file.Write( buf, strlen(buf) );
	} catch( CFileException* ) {
		OutputErrMsg( "failed to write to file: %s", (LPCTSTR)m_file.GetFilePath() );
	}
}

// add beginning "\t" & ending "/r/n" manually
void CAsmCodeGenerator::emitCode( CString& code )
{
	ASSERT( m_file.m_hFile != CFile::hFileNull );

	try {
		m_file.Write( (LPCTSTR)code, code.GetLength() );
	} catch( CFileException* ) {
		OutputErrMsg( "failed to write to file: %s", (LPCTSTR)m_file.GetFilePath() );
	}
}

/*  *    CAsmCodeGenerator
    *    80x86 ASM routines
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.21             */

// read a character
// use AX register, result is stored in AL
void CAsmCodeGenerator::_inline_readc()
{
	CString temp = "	mov		ah, 1\r\n"
				   "	int		21h\r\n"
				   "	mov		ah, 0\r\n";
	emitCode( temp );
}

// read a integer
// need:
// data segment
// buf		db	64 dup(?)
// count	dw	?
void CAsmCodeGenerator::_readi()
{
	CString temp = ";----------------------------------------------------\r\n"
		           "; GENERAL PRUPOSE ROUTINES\r\n"
				   ";----------------------------------------------------\r\n"
				   "; FOR READI\r\n"
				   ";----------------------------------------------------\r\n"
				   ";input a decimal, result in AX\r\n"
				   "_call_readi_	proc	near pascal uses bx cx dx si\r\n"
				   "	mov		count, 0\r\n"
				   "readi@next:\r\n"
				   "	mov		ah, 7\r\n"
				   "	int		21h\r\n"
				   "	cmp		al, '-'\r\n"
				   "	je		readi@onCHAR\r\n"
				   "	cmp		al, '+'\r\n"
				   "	je		readi@onCHAR\r\n"
				   "	cmp		al, 08h	;DEL\r\n"
				   "	je		readi@onDEL\r\n"
				   "	cmp		al, 0dh	;CR\r\n"
				   "	je		readi@onCR\r\n"
				   "	cmp		al, '0'\r\n"
				   "	jb		readi@next\r\n"
				   "	cmp		al, '9'\r\n"
				   "	ja		readi@next\r\n"
				   "readi@onCHAR:\r\n"
				   "	cmp		count, 63\r\n"
				   "	jae		readi@next\r\n"
			   	   ";process the key input, and show it on screen\r\n"
				   "	mov		si, count\r\n"
				   "	inc 	count\r\n"
				   "	mov		buf[si], al\r\n"
				   "	mov		dl, al\r\n"
				   "	mov		ah, 02h\r\n"
				   "	int		21h\r\n"
				   "	jmp		readi@next\r\n"
				   "readi@onDEL:\r\n"
				   "	call	keydel\r\n"
				   "	jmp		readi@next\r\n"
				   "readi@onCR:\r\n"
				   "	mov		ah, 2\r\n"
				   "	mov		dl, 0ah\r\n"
				   "	int		21h\r\n"
				   "	mov		dl, 0dh\r\n"
				   "	int		21h\r\n"
				   "	mov		si, count\r\n"
				   "	mov		buf[si], 0\r\n"
				   "	call	str2dec\r\n"
				   "	ret\r\n"
				   "_call_readi_	endp\r\n"
				   ";----------------------------------------------------\r\n"
				   ";set the cursor in DX\r\n"
				   "set_cur		proc	near pascal uses ax bx\r\n"
				   "	mov		bh, 0\r\n"
				   "	mov		ah, 02h\r\n"
				   "	int		10h\r\n"
				   "	ret\r\n"
				   "set_cur	endp\r\n"
				   ";----------------------------------------------------\r\n"
				   ";read current cursor to DX\r\n"
				   "read_cur	proc	near pascal uses ax bx cx\r\n"
				   "	mov		bh, 0\r\n"
				   "	mov		ah, 03h\r\n"
				   "	int		10h\r\n"
				   "	ret\r\n"
				   "read_cur endp\r\n"
				   ";----------------------------------------------------\r\n"
				   ";procedure for key DEL\r\n"
				   "keydel		proc	near pascal uses bx cx dx\r\n"
				   "	cmp		count, 0\r\n"
				   "	jle		keydel@ret\r\n"
				   "	dec		count\r\n"
				   "	call	read_cur\r\n"
				   "	dec		dl\r\n"
				   "	call	set_cur\r\n"
				   "	mov		bh, 0\r\n"
				   "	mov		al, 20h\r\n"
				   "	mov		cx, 1\r\n"
				   "	mov		ah, 0ah\r\n"
				   "	int		10h\r\n"
				   "keydel@ret:	\r\n"
				   "	ret\r\n"
				   "keydel	endp\r\n"
				   ";----------------------------------------------------\r\n"
				   ";result in AX\r\n"
				   "str2dec		proc	near pascal uses bx cx dx si\r\n"
				   "	local	minus:byte\r\n"
				   ";init\r\n"
				   "	mov		minus, 0\r\n"
				   "	mov		ax, 0\r\n"
				   "	mov		bx, 10\r\n"
				   "	mov		cx, 0\r\n"
				   ";\r\n"
				   "	cmp		count, 0\r\n"
				   "	je		str2dec@ret\r\n"
				   "	mov		si, 0\r\n"
				   "	cmp		buf[si], '-'\r\n"
				   "	je		str2dec@onMINUS\r\n"
				   "	cmp		buf[si], '+'\r\n"
				   "	je		str2dec@onPLUS\r\n"
				   "str2dec@next:\r\n"
				   "	cmp		buf[si], '0'\r\n"
				   "	jb		str2dec@complete\r\n"
				   "	cmp		buf[si], '9'\r\n"
				   "	ja		str2dec@complete\r\n"
				   "	mul		bx\r\n"
				   "	mov		cx, ax\r\n"
				   "	mov		al, buf[si]\r\n"
				   "	sub		al, '0'\r\n"
				   "	mov		ah, 0\r\n"
				   "	add		ax, cx\r\n"
				   "	inc		si\r\n"
				   "	jmp		str2dec@next\r\n"
				   "str2dec@onMINUS:\r\n"
				   "	mov		minus, 1\r\n"
				   "	inc		si\r\n"
				   "	jmp		str2dec@next\r\n"
				   "str2dec@onPLUS:\r\n"
				   "	inc		si\r\n"
				   "	jmp		str2dec@next\r\n"
				   "str2dec@complete:\r\n"
				   "	cmp		minus, 1\r\n"
				   "	jne		str2dec@ret\r\n"
				   "	mov		cx, ax\r\n"
				   "	mov		ax, 0\r\n"
				   "	sub		ax, cx\r\n"
				   "str2dec@ret:\r\n"
				   "	ret\r\n"
				   "str2dec	endp\r\n";
	emitCode( temp );
}

// print the integer in BX
void CAsmCodeGenerator::_writei()
{
	CString temp = ";----------------------------------------------------\r\n"
				   "; FOR WRITEI\r\n"
				   ";----------------------------------------------------\r\n"
				   ";show decimal in BX\r\n"
				   "_call_showi_	proc	near pascal uses ax cx dx\r\n"
				   "	local	can_show:byte\r\n"
				   "	mov		can_show, 0\r\n"
				   "	cmp		bx, 0\r\n"
				   "	jge		show@show\r\n"
				   "	mov		ax, bx\r\n"
				   "	mov		bx, 0\r\n"
				   "	sub		bx, ax\r\n"
				   "	mov		ah, 2\r\n"
				   "	mov		dl, '-'\r\n"
				   "	int		21h\r\n"
				   "show@show:\r\n"
				   "	mov		cx, 10000d\r\n"
				   "	cmp		bx, cx\r\n"
				   "	jb		show@1\r\n"
				   "	mov		can_show, 1\r\n"
				   "	call	dec_div\r\n"
				   "show@1:\r\n"
				   "	mov		cx, 1000d\r\n"
				   "	cmp		can_show, 1\r\n"
				   "	je		show@2\r\n"
				   "	cmp		bx, cx\r\n"
				   "	jb		show@3\r\n"
				   "	mov		can_show, 1\r\n"
				   "show@2:\r\n"
				   "	call	dec_div\r\n"
				   "show@3:\r\n"
				   "	mov		cx, 100d\r\n"
				   "	cmp		can_show, 1\r\n"
				   "	je		show@4\r\n"
				   "	cmp		bx, cx\r\n"
				   "	jb		show@5\r\n"
				   "	mov		can_show, 1\r\n"
				   "show@4:\r\n"
				   "	call	dec_div\r\n"
				   "show@5:\r\n"
				   "	mov		cx, 10d\r\n"
				   "	cmp		can_show, 1\r\n"
				   "	je		show@6\r\n"
				   "	cmp		bx, cx\r\n"
				   "	jb		show@7\r\n"
				   "	mov		can_show, 1\r\n"
				   "show@6:\r\n"
				   "	call	dec_div\r\n"
				   "show@7:\r\n"
				   "	mov		cx, 1d\r\n"
				   "	call	dec_div\r\n"
				   "	ret\r\n"
				   "_call_showi_	endp\r\n"
				   ";----------------------------------------------------\r\n"
				   "dec_div	proc	near pascal uses ax\r\n"
				   "	mov		ax, bx\r\n"
				   "	mov		dx, 0\r\n"
				   "	div		cx\r\n"
				   "	mov		bx, dx\r\n"
				   "	mov		dl, al\r\n"
				   "	add		dl, 30h\r\n"
				   "	mov		ah, 2\r\n"
				   "	int		21h\r\n"
				   "dec_div@ret:\r\n"
				   "	ret\r\n"
				   "dec_div	endp\r\n";
	emitCode( temp );
}

/*  *    CAsmCodeGenerator
    *    code generation routines
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.21             */

// generate data segment for global data and data in _main()
void CAsmCodeGenerator::genPreSeg()
{
	CTreeNode *p = NULL, *t = NULL;
	// add variables used in default routines
	CString temp = "	.model	small\r\n"
				   "	.386\r\n"
				   "	.stack	200h\r\n"
				   ";----------------------------------------------------\r\n"
				   "	.data\r\n"
				   ";variables used in _call_readi_ routine\r\n"
		           "buf		db	64 dup(?)\r\n"
				   "count	dw	?\r\n"
				   ";return values\r\n"
				   "_return	dw	?\r\n"
				   ";global and _main variables\r\n";
	emitCode( temp );
	// add global and _main variables
	p = m_pAnalyzer->m_pProgram;
	while( p ) {
		if( p->nodekind == kVarDec ) genData( p );
		else if( p->szName == "main" ) {
			t = p->child[0]; // main(...) parameters, common none
			while( t ) {
				genData( t );
				t = t->sibling;
			}
			t = p->child[1]; // local variables in _main
			while( t ) {
				if( t->nodekind == kVarDec ) genData( t );
				t = t->sibling;
			}
		}
		p = p->sibling;
	}
	// end of data segment
}

// generate an item in data segment for node p
// all types use the same type "DW"
void CAsmCodeGenerator::genData( CTreeNode* p )
{
	CString temp1, temp2;
	if( p->bArray ) temp1.Format( "%d dup(?)", p->iArraySize );
	else temp1.Format( "?" );
	temp2.Format( "%s@%s\tdw\t%s\r\n", (LPCTSTR)p->szScope, (LPCTSTR)p->szName, (LPCTSTR)temp1 );
	emitCode( temp2 );
}

// generate code segment
void CAsmCodeGenerator::genCodeSeg()
{
	CString temp = ";----------------------------------------------------\r\n"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -