📄 assembler.cpp
字号:
#include "assembler.h"
Assembler::Assembler()
{
InitTwoTables(); //初始化预测分析表和语法规则表
InitRegsAlias(); //初始化寄存器编号与别名对应表
GenFiles();
TOKEN.TokenID = 0;
TOKEN.TokenName = "";
No_Com = 0; //指令行编号
No_Var = 0; //变量行编号
No_TxtLine = 0;
for ( int z = 0; z < RamSize; z++ )
{
CodeUnitUsed[z] = false;
DataUnitUsed[z] = false;
}
}
Assembler::~Assembler()
{
ShutFiles();
}
void Assembler::Parser( FILE* SourceFileName )
{
int v = SyntacticAnalysis(SourceFileName);
if ( v != 0 )
{
cout << "Error occurs...SyntacticAnalysis' return value: " << v << endl;
ErrorProcess(v);
}
else
cout << "Succeed!" << endl;
}
int Assembler::SyntacticAnalysis( FILE * SourceFileName )
{
int i;
int LastRule;
int dataline = 0; //用以指示数据文件的行数
TOKEN.TokenID = 0;
STACK.push(-1);
STACK.push(N_PRO);
// CMD是32位char类型,存放最新已经语法分析得到的指令的二进制码,初始化为'0'
for ( i = 0; i < 32; i++ )
CMD[i] = '0';
// 调用词法分析器Scanner,依据栈顶符号<N_PRO>,从源程序中读取第一个
// 单词入TOKEN中,如果返回-1,表示源程序中有词法错误
if ( Scanner(STACK.top(), SourceFileName) )
return ERROR_LEX;
//cout << TOKEN.TokenID << '\t' << TOKEN.TokenName << endl;
//开始LL(1)分析,包含调用词法分析器Scanner和指令翻译器ConstructCMD
while (1)
{
if ( STACK.top() == -1 ) //若栈空,且当前读入源程序单词为-1,则语法分析完成,并正确
{
// fprintf( DataFile, "END;" ); //写入数据文件最后一个单词"END"
// 以下是写数据文件的结尾,因为程序文件是一次性写的,所以它的起始和结尾都是在同一个函数WriteProg()中完成的
fprintf( DataFile, " [" );
fprintf( DataFile, "% x", No_Var );
fprintf( DataFile, "..3FF] : 00000000;\nENDS;" );
int rrt = WriteProg();
if ( rrt == -1 ) //将指令写入程序文件,返回值为-1,表示地址交迭
return ERROR_CODE_ADDR_OVERLAPPED;
else if ( rrt == -2 ) //将指令写入程序文件,返回值为-2,表示有转移指令引用不存在的指令标号名
return ERROR_NOTEXIST_SEGID;
return 0; //汇编过程成功退出
}
if ( STACK.top() > CountOfVT )
//如果当前栈顶为VN,则查预测分析表
{
// if ( (STACK.empty()) || (TOKEN.TokenID == -1) )
//若栈空,且当前读入源程序单词为-1,则语法分析完成,并正确
if ( ForcastTable[STACK.top()-CountOfVT][TOKEN.TokenID] == 0 )
return ERROR_SEMANTIC;
else
{
LastRule = ForcastTable[STACK.top()-CountOfVT][TOKEN.TokenID]; //记录编号
// cout << "NT:LastRule: " << LastRule << "\tTOKEN.TokenID: " << TOKEN.TokenID << endl;
if ( Deduction(ForcastTable[STACK.top()-CountOfVT][TOKEN.TokenID]) == 5 )
return ERROR_DEDUCTION;
continue;
}
}
else
//当前栈顶为VT,则匹配,并翻译
{
if ( STACK.top() == TOKEN.TokenID )
//当栈顶为终结符,并和当前读取的单词同,则匹配
{
// store segids with SEGID
if ( LastRule == 27 && TOKEN.TokenID == T_IDNAME )
//如果最近采用的是27号产生式,则IDNAME是指令标号,
//顺序保存到标号表SEGID
if ( AddNormalSegID() )
return ERROR_REIDNAME; //如果标号有重复则错误退出
if ( LastRule == 15 && TOKEN.TokenID == T_IDNAME )
//如果最近采用的是15号产生式,则IDNAME是起始指令标号,
//保存到标号表SEGID的最前面
if ( AddStartSegID() )
return ERROR_REIDNAMES; //如果标号有重复则错误退出
if ( ( LastRule == 36 || LastRule == 42 ) && TOKEN.TokenID == T_IDNAME ) //J,JAL,BEQ,BNE中遇到IDNAME,需要回填
//如果最近采用的是36号产生式,则IDNAME是转移的目的标号
//保存到回填表BACKTABLE中
if ( AddBackID() )
return ERROR_BACK; //添加失败则错误退出
/////////////TRANSLATATION/////////////////////////////////////
//////////SEMANTICS RULES OF <N_COM> RULES/////////////////////
if ( LastRule == 17 || LastRule == 18 || LastRule == 19
|| LastRule == 20 || LastRule == 21 || LastRule == 22
|| LastRule == 23 || LastRule == 30 || LastRule == 32
|| LastRule == 33 || LastRule == 34 || LastRule == 35
|| LastRule == 37 ||LastRule == 36 || LastRule == 38
|| LastRule == 39 || LastRule == 40 || LastRule == 41 || LastRule == 42 || LastRule == 43 ) //表明当前读取的是指令 LastRule == 36,23|| ??? J,JAL,BEQ,BNE中遇到IDNAME,需要回填
{
/* cout << "VT:LastRule: " << LastRule << endl
<< "STACK.top(): " << STACK.top() << endl
<< "TOKEN.TokenID: " << TOKEN.TokenID << endl
<< "TOKEN.TokenName: " << TOKEN.TokenName << endl;
*/ if ( STACK.top() != T_ENDL ) //如果当前读取的不是指令结束的单词,则翻译
{
if ( ConstructCMD() ) // 将当前单词翻译为二进制码,存入CMD,注意这些函数是成功时才返回0,否则返回非零值
return ERROR_CONCMD; //翻译失败退出
}
else if ( STACK.top() == T_ENDL )
//当前读取的是指令结束的单词,则CMD保存了一个完整指令的二进制码,并且当前TOKEN.TokenName串中保存的就是用户解释
{
if ( ConstructCOMMANDS() )
//将CMD按照指令顺序保存到指令链COMMANDS
return ERROR_CONCMDS;
// cout << "after concmds: " << endl;
}
}
////////
////////
if ( LastRule == 9 && STACK.top() == T_IDNAME )
//如果当前读取的是标识符,且产生式为9号
//则说明当前是定义变量,将变量标识符保存到VAR
if ( StoreVar() )
return ERROR_DEFVAR; //变量定义错误
////////
////////
if ( LastRule == 9 && STACK.top() == T_32NUM )
//如果当前读取的是32位数据,且产生式为9号
//则说明当前是定义变量,将值输出到数据文件
{
if ( DataUnitUsed[No_Var] == true )
return ERROR_DATA_ADDR_OVERLAPPED;
if ( dataline != No_Var )
{
if ( dataline == No_Var - 1 )
{
fprintf( DataFile, "\t" );
fprintf( DataFile, "% x", dataline );
fprintf( DataFile, " : \t00000000;\n" );
}
else
{
fprintf( DataFile, "\t\t[" );
fprintf( DataFile, "% x", dataline );
fprintf( DataFile, ".." );
fprintf( DataFile, "% x", No_Var - 1 );
fprintf( DataFile, "] : 00000000;\n" );
}
dataline = No_Var;
}
fprintf( DataFile, " " );
fprintf( DataFile, "% x", No_Var );
fprintf( DataFile, " : " );
fprintf( DataFile, TOKEN.TokenName );
fprintf( DataFile, ";\n" );
DataUnitUsed[No_Var] = true;
No_Var++;
dataline++;
}
//////////////////////
//////////////////////以下是由读入的ADDR来设置指令地址No_Com和数据地址No_Var
if ( LastRule == 5 && STACK.top() == T_ADDR ) //数据地址
{
int tempv = AddrToInt( TOKEN.TokenName );
if ( tempv % 4 != 0 ) //如果地址不能被4整除,则返回错误
return ERROR_DATA_ADDR;
No_Var = tempv/4;
}
if ( LastRule == 13 &&STACK.top() == T_ADDR ) //指令地址
{
int tempc = AddrToInt( TOKEN.TokenName );
// cout << tempc << endl;
if ( tempc % 4 != 0 ) //如果地址不能被4整除,则返回错误
return ERROR_CODE_ADDR;
No_Com = tempc/4;
}
///////////////////////////////////////////////////////
STACK.pop(); //匹配完成弹出栈顶元素
if ( STACK.top() == -1 )
{
// cout << "stack is empty" << endl;
continue;
}
// cout << "After pop stack, top is " << STACK.top() << endl;
if ( Scanner(STACK.top(), SourceFileName) )
{
return ERROR_LEX;
}
// cout << "after scanner: " << TOKEN.TokenID << '\t' << TOKEN.TokenName << endl;
}
else //栈顶为终结符,并和当前读取的单词不同,则匹配失败
{
return ERROR_SEMANTIC;
}
}
} // end while
return -1;
}
int Assembler::Scanner(int TypeOfToken,FILE *SourceFileName)
{
int State=0;
static char ret[256];
int i = 0;
int times = 0;
if ( TypeOfToken > CountOfVT ) //当前栈顶符号为非终结符
{
switch ( TypeOfToken-CountOfVT )
{
case 1: //当前栈顶符号为<N_PRO>
case 2: //当前栈顶符号为<N_DATA>
{ //扫描DATA或CODE单词
char ch = ReadOneChar(SourceFileName);
if ( ch == '\n' )
No_TxtLine++;
while ( 1 )
{
switch ( ch )
{
case 'd':
case 'D':
{
if(State==0) {State=1;break;}
if(State==6) {State=7;break;}
else return -1;
}
case 'a':
case 'A':
{
if(State==1) {State=2;break;}
if(State==3) {State=4;break;}
else return -1;
}
case 't':
case 'T':
{
if(State==2) {State=3;break;}
else return -1;
}
case 'c':
case 'C':
{
if(State==0) {State=5;break;}
else return -1;
}
case 'o':
case 'O':
{
if(State==5) {State=6;break;}
else return -1;
}
case 'e':
case 'E':
{
if(State==7) {State=8;break;}
else return -1;
}
case ' ':
case '\t':
// case '\n':
{
if(State==4){TOKEN.TokenID=1;TOKEN.TokenName="DATA";return 0;}
if(State==8){TOKEN.TokenID=1;TOKEN.TokenName="CODE";return 0;}
else return -1;
}
default: return -1;
}
ch = getc( SourceFileName );
if ( ch == '\n' )
No_TxtLine++;
}
break;
}
case 4: //当前栈顶符号为<N_DATASEG>
case 9: //当前栈顶符号为<N_DATAENDS>
{ //根据预测分析表,以上两种情况应该扫描DATA单词
char ch = ReadOneChar(SourceFileName);
if ( ch == '\n' )
No_TxtLine++;
while ( 1 )
{
switch ( ch )
{
case 'd':
case 'D':
{
if(State==0) {State=1;break;}
else return -1;
}
case 'a':
case 'A':
{
if(State==1) {State=2;break;}
if(State==3) {State=4;break;}
else return -1;
}
case 't':
case 'T':
{
if(State==2) {State=3;break;}
else return -1;
}
case ' ':
case '\t':
// case '\n':
{
if(State==4){TOKEN.TokenID=1;TOKEN.TokenName="DATA";return 0;}
else return -1;
}
default: return -1;
}
ch = getc(SourceFileName);
if ( ch == '\n' )
No_TxtLine++;
}
break;
}
case 5: //当前栈顶符号为<N_ORG_DATA>
{ //应该扫描ORG_DATA单词
char ch = ReadOneChar(SourceFileName);
if ( ch == '\n' )
No_TxtLine++;
while ( 1 )
{
switch ( ch )
{
case 'o':
case 'O':
{
if(State==0) {State=1;break;}
else return -1;
}
case 'r':
case 'R':
{
if(State==1) {State=2;break;}
else return -1;
}
case 'g':
case 'G':
{
if(State==2) {State=3;break;}
else return -1;
}
case '_':
{
if(State==3) {State=4;break;}
else return -1;
}
case 'd':
case 'D':
{
if(State==4) {State=5;break;}
else return -1;
}
case 'a':
case 'A':
{
if(State==5) {State=6;break;}
if(State==7) {State=8;break;}
else return -1;
}
case 't':
case 'T':
{
if(State==6) {State=7;break;}
else return -1;
}
case ' ':
case '\t':
// case '\n':
{
if(State==8){TOKEN.TokenID=2;TOKEN.TokenName="ORG_DATA";return 0;}
else return -1;
}
default:return -1;
}
ch = getc(SourceFileName);
if ( ch == '\n' )
No_TxtLine++;
}
break;
}
case 6: //当前栈顶符号为<N_PRO>
case 8: //当前栈顶符号为<N_VAR>
case 13: //当前栈顶符号为<N_SEG>
case 14: //当前栈顶符号为<N_START SEGID>
case 18: //当前栈顶符号为<N_SUBSEGID>
{ //以上五种情况,应该扫描IDNAME单词
i = 0;
char ch = ReadOneChar( SourceFileName );
if ( ch == '\n' )
No_TxtLine++;
ret[i++] = ch;
while ( 1 )
{
if ( ((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')) && (State==0||State==1) )
{
State = 1;
ch = getc( SourceFileName );
if ( ch == '\n' )
No_TxtLine++;
ret[i++] = ch;
continue;
}
if ( (ch>='0'&&ch<='9') && State == 1 )
{
State = 1;
ch = getc( SourceFileName );
if ( ch == '\n' )
No_TxtLine++;
ret[i++] = ch;
continue;
}
if ( State == 1 )
if ( ungetc(ch, SourceFileName) )
{
if ( ch == '\n' )
No_TxtLine--;
ret[--i]='\0';
TOKEN.TokenID=3;
TOKEN.TokenName=ret;
return 0;
}
else
return -1;
else
return -1;
}
break;
}
case 7: //当前栈顶符号为<N_VARS>'
{ //应该扫描DATA或IDNAME单词
i = 0;
char ch=ReadOneChar(SourceFileName);
if ( ungetc(ch, SourceFileName) == 0 ) return -1;
while ( 1 )
{
ch = getc( SourceFileName );
if ( ch == '\n' )
No_TxtLine++;
ret[i++] = ch;
switch ( ch )
{
case 'd':
case 'D':
{
if(State==0) {State=1;break;}
if(State==1) {State=5;break;}
if(State==2) {State=5;break;}
if(State==3) {State=5;break;}
if(State==4) {State=5;break;}
if(State==5) {State=5;break;}
return -1;
}
case 'a':
case 'A':
{
if(State==1) {State=2;break;}
if(State==0) {State=5;break;}
if(State==2) {State=5;break;}
if(State==3) {State=4;break;}
if(State==4) {State=5;break;}
if(State==5) {State=5;break;}
return -1;
}
case 't':
case 'T':
{
if(State==2) {State=3;break;}
if(State==0) {State=5;break;}
if(State==1) {State=5;break;}
if(State==3) {State=5;break;}
if(State==4) {State=5;break;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -