📄 asmcodegenerator.cpp
字号:
// 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 + -