📄 masmber_c5.cpp
字号:
//---------------------------------------------------------------------------
// MAsmber_C5.cpp
//---------------------------------------------------------------------------
#include "MAsmber_H.h"
#include "AsmF_H.h"
#include "OBJfile_H.h"
#include "ListFile_H.h"
#include "OBJModule_H.h"
//---------------------------------------------------------------------------
#define DebugKit(str) DebugMsg(str)
//---------------------------------------------------------------------------
// 产生OBJ文件。
// 流程:
// (1) 打开OBJ文件。
// (2) 写入一个文件头。
// (3) 写入模块信息。
// (4) 关闭OBJ文件。
//---------------------------------------------------------------------------
void MacroAsmber::GenOBJFile()
{ if(!ObjFile) { return; } // endif 开关没打开
objFilePt->Open(); // 打开文件。
Jstring CommandLine("");
for(int16u i = 0; i < Margc; ++i) // 记录命令行参数
{ CommandLine = CommandLine + Margv[i] + " "; } // end for
objFilePt->WriteFileHeaderRecord(CommandLine, *AsmFn); // 写文件头
JModulePt->WriteModuleToOBJFile(); // 往目标文件写入一个模块!! (核心!)
objFilePt->Close(); // 关闭文件。
} // end GenOBJFile
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 汇编流程总调度。
// 流程:
// (1) 提取不带后缀名的Pname。
// (2) 初始化,创建各对象。
// (3) 将命令行输入的参数转换成汇编行。
// (4) 词法分析。
// (5) 装载8051的SFR符号。
// (6) 语法分析。
// (7) 语义分析。
// (8) 代码生成。
// (9) 对符号链表进行排序。
// (10)产生OBJ文件。
// (11)产生列表文件。
//---------------------------------------------------------------------------
ERR MacroAsmber::AssembleFile(const Jstring& FileNam)
{ FetchPname(FileNam, Pname); // 为Pname赋值。如果FileNam有后缀名,Pname不包括后缀名。
Jstring Srcfilename(FileNam);
if(Pname == FileNam) // 如果没有后缀名
{ Srcfilename = Srcfilename + ".asm"; } // endif
AsmFn = new AsmFile(*this, Srcfilename); // 建立一个源Asm文件对象
objFilePt = new OBJfile(*this, Pname); // 创建OBJ文件
LstFilePt = new LISTFile(*this, Pname); // 创建LST文件
JModulePt = new OBJmodule(*this, Pname); // 创建一个默认的当前模块
SegPt = JModulePt->SegDefHead; // 给当前段指针赋初值,是一个绝对段
printf("\nAssembling file %s...",AsmFn->FileName());
CommandLineToAsmL(); // 将命令行输入的参数转换成汇编行。在词法分析之前做。
ERR era = FileToToken(); // 词法分析, 该函数会影响Ln的值。
DebugMsg(printf("\nFile lex %s! ", era ? "Error" : "Ok" );); // debug
if(era) { goto enden; } // endif
++AsmFn->runCount; // 1
if(SFR51) // 是否装载8051的SFR符号。在词法分析之后做。
{ LabMger->LoadSFR51(SRegAddr); } // endif
era = AsmFileParse(); // 语法分析
DebugMsg(printf("\nFile parse %s! ", era ? "Error" : "Ok" );); // debug
if(era) { goto enden; } // endif
++AsmFn->runCount; // 2
era = MeaningTrans(); // 语义分析
DebugMsg(printf("\nMeaningTrans %s! ", era ? "Error" : "Ok" );); // debug
if(era) { goto enden; } // endif
++AsmFn->runCount; // 3
era = FileToObjCode(); // 代码生成
DebugMsg(printf("\nToObjCode %s! ", era ? "Error" : "Ok" );); // debug
if(era) { goto enden; } // endif
++AsmFn->runCount; // 4
//JModulePt->show(); Debugkey;
//AsmFn->ShowFileToken(); Debugkey;
// LabMger->ShowLabelList(); Debugkey;
enden:
LabMger->SortLabelByCrno(); // 对链表进行排序。在产生OBJ文件和列表文件之前做。
if(!era) { GenOBJFile(); } // endif // 产生OBJ文件。
GenListFile(); // 产生列表文件。
fprintf(EpFile.GetEPfile(),"\nTotal %d errors, %d warnings.", GetErrorSum(), GetWarningSum());
if(!EpFile.IsEPScreen())
{ printf("\nTotal %d errors, %d warnings.", GetErrorSum(), GetWarningSum());
EpFile.Close();
if(GetErrorSum() + GetWarningSum() == 0) { EpFile.Suicide(); } // endif
} // endif
return era;
} // end ComplyFile
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 建立符号表。
// 从文件头开始扫描,把所有的标号、常量、变量都登记起来。如果能计算的,马上计算。
// 不能计算的,忽略。
// 注意, 必须在汇编行语法分析完全正确的前提下进行!
// Fn 要预先设置好!Ln 被修改。
// 流程:
// (1) 初始化。(置SegPt指针,设置默认段段中新片段。)
// (2) 汇编行的lc值被赋成当前段的当前地址计数值,并置LnOK。
// (3) 汇编行语义分析。
// (4) 循环。
// (5) 更新段大小。
// (6) 关闭最后一个使用的段的片段。
// (7) 整理符号表。
//---------------------------------------------------------------------------
ERR MacroAsmber::MeaningTrans()
{ Pass = false;
DebugMsg("\n\t\t\t\t(Pass 2)"; Debugkey;); // debug
ERR erra = OK_no_Err;
Ln = AsmFn->FirstLine(); // 从文件的第一汇编行开始, SegPt->SegLc地址预置初值
SegPt = JModulePt->SegDefHead; // 给当前段指针赋初值, 指向默认段
SegPt->InitSegTrpHead(Ln); // Pass2 设置默认段段中新片段。
for( ; Ln; Ln = Ln->next ) // 全文件扫描
{ // 第二遍扫描,汇编行的lc值被赋成当前段的当前地址计数值,并置LnOK。
// Pass2, Ln->IsOK 之前是false。
Ln->lc = SegPt->SegLc; Ln->IsOK = true;
ERR err = AsmLineMeaningAct();
if( err )
{ DebugKit( printf("\tErr:%d!",err); );
erra = Have_Errs; } // endif
} // end for
// 退出循环后,SegPt当前段的地址计数器存有最大地址值。
SegPt->UpdateSegSize(); // 根据SegLc更新段大小,保存上一段的最大地址
SegPt->CloseCurrentSegTrp(AsmFn->Tail); // 关闭最后一个使用的段的片段。
DebugMsg(printf("\n(Pass 2)FileFindVar pass=false err = %d", erra); Debugkey;); // debug
// AsmFn->ShowFileToken(); Debugkey;
// LabMger->ShowLabelList(); Debugkey;
// JModulePt->show(); Debugkey;
if(!erra) { erra = LabMger->LabelFresh(); } // endif
return erra;
} // end MeaningTrans
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 输出警告信息。
//---------------------------------------------------------------------------
void MacroAsmber::OutWarning(int8u warn)
{ if(warn > WarningNUM){ warn = WarningNUM; } // endif Just for Debug!!
AsmFn->AddWarn(Ln->LineNo,warn);
if(ErrPrint)
{ fprintf( EpFile.GetEPfile(), "\n*** Warning(Line %u, %s): ",
Ln->LineNo, (const char*)AsmFn->FileName );
fprintf( EpFile.GetEPfile(), ErrWarnMsg::warnmsg[warn] );
} // endif
} // end OutWarning
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 输出错误信息。
//---------------------------------------------------------------------------
void MacroAsmber::OutputErr(int8u errno)
{ if(errno > ERRmsgSum){ errno = ERRmsgSum + 1 ; } // endif Just for Debug!!
AsmFn->AddErr(Ln->LineNo,errno);
if(ErrPrint)
{ fprintf( EpFile.GetEPfile(), "\n*** ERROR(Line %u, %s): ",
Ln->LineNo, (const char*)AsmFn->FileName );
fprintf( EpFile.GetEPfile(), ErrWarnMsg::errmsg[errno] );
} // endif
} // end OutputErr
//---------------------------------------------------------------------------
#include "OBJfile_H.h"
//---------------------------------------------------------------------------
//
// OBJ文件生成器
//
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 产生列表文件。
// 流程:
// (1)初始化。打开列表文件。
// (2)产生列表头。
// (3)产生OBJ目标码。
// (4)产生符号表。
// (5)产生使用的寄存器组号。
// (6)产生列表小结。
// (7)关闭文件。
//---------------------------------------------------------------------------
void MacroAsmber::GenListFile()
{ if(!LstFile) { return; } // endif
rewind(AsmFn->FilePt); // 从文件头开始读入
LstFilePt->OpenFileForWrite(); // 为OutputFile赋初值。
LstFilePt->GenListHeader();
LstFilePt->GenOBJList();
LstFilePt->PrintSymbolTable();
LstFilePt->GenRegBankUsed();
fprintf(LstFilePt->OutputFile,"\n\nTotal %d error(s), %d warning(s). ",
AsmFn->ErrorSum(), AsmFn->WarningSum());
if(AsmFn->ErrorSum()==0)
{ fprintf(LstFilePt->OutputFile,"== << Assembly complete. >> =="); } // endif
else
{ fprintf(LstFilePt->OutputFile,">> Please check your program. <<"); } // end else
fprintf(LstFilePt->OutputFile,
"\n==================== << End of list >> ========================",
(const char*)LstFilePt->FileName );
LstFilePt->CloseFile();
printf("\nLIST file has been written to %s.",(const char*)LstFilePt->FileName);
} // end GenListFile
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 输入文件名, 把它包含过来。
// 注意,该函数使用Ln,影响Ln。
//---------------------------------------------------------------------------
ERR MacroAsmber::MC_Include(const Jstring& filename)
{ if(++IncFnNest > MaxIncFnNest)
{ FatalErr("\nINCLUDE file nest too deep!"); } // endif
FILE* IncFnPt = fopen((const char*)filename,"r"); // 给文件句柄赋值。
if(IncFnPt == NULL)
{ printf("\nCannot open file %s!",filename());
return Have_Errs;
} // endif
AsmLine* IncLine = Ln; // 保存当前的汇编行。
AsmLine* LastLine = Ln; // 保存上一行。
ERR erra = OK_no_Err; //
bool cont = true; // 在没有遇到END之前,该值为true。
while(!feof(IncFnPt) && cont) // 把整个文件转换成Token流。
{ // ............................................
Ln = new AsmLine; // 创建新汇编行对象
Ln->LineNo = IncLine->LineNo; // 给新行赋行号值
//Ln->NestNo = 0; //
Ln->Includ = true; // 打上一个标记
char* textbuf = AsmFn->buff; // 使用了AsmFn的缓冲区
fgets(textbuf, LineReadBufferSize, IncFnPt);
textbuf[LineReadBufferSize-1]='\0'; // 缓冲区最终端填字串尾。
register char* p = textbuf + strlen(textbuf) - 1;
if( *p == '\n' ) { *p = '\0'; } // endif // p 指向读入行最后一个字符。
// Now, 已读入了一行文本到textbuf。
Ln->head->Name = textbuf; // 它的头节点装有源文本
// 把ASCII文本字串转换成汇编行。
ERR err = StrLexToAsmline(textbuf, Ln, AsmFn->CommentEnable); // 带回err值。
switch(err)
{ case 0 : { break; } // end case
case 2 : { cont = false; break; } // end case
default : { erra = Have_Errs; } // end default
} // end switch
if(Ln->HeadToken()== MacroCTRLn && MajorCtrlParse(Ln) ) // 首要控制指令
{ erra = Have_Errs; } // endif
if(Ln->TknLNotEmpty() && cont) // 如果不是只有一个头结点的话, 汇编行加进AsmFile中。
{ AsmFn->InsertAsmLine(Ln, LastLine);
LastLine = Ln;
} // endif // "END"也不能加进去。
else // 只有一个头结点的汇编行不添加到AsmFile中.
{ delete Ln; Ln = LastLine; } // end else
// ............................................
} // end while
// Now, the file has been transfered to AsmFile.
Ln = IncLine;
if( fclose(IncFnPt) )
{ printf("\nClose file %s error.",filename()); } // endif
return erra;
} // MC_Include
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// end MAsmber_C5.cpp
//---------------------------------------------------------------------------
// Written by JamesyFront. ZLGmcu Dev.Co.Ltd. 2002.
//---------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -