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

📄 macromanager_c.cpp

📁 MCS-51单片机宏汇编器源程序,单片机初学者必看
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//---------------------------------------------------------------------------
//  MacroManager_C.cpp 
//---------------------------------------------------------------------------
#include "JsGlobal_H.h"
#include "AsmF_H.h"
#include "MacroManager_H.h"
#include "MAsmber_H.h"
//---------------------------------------------------------------------------
//
//                       宏指令处理器
//
//---------------------------------------------------------------------------
#define DebugKit(str)       DebugMsg(str)
//---------------------------------------------------------------------------
//                         MacrosManager
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// 寻找LOCAL语句。有局参则改成ArgvWordkn。
// 输入局参指针LocalarguPt,返回被赋值后的局参链头指针。
// 输入原有名字链的指针PreNamesSetPt。(可以为NULL。)
// Ln不能为空。 Ln带值返回。返回时Ln指向LOCAL的下一行。
// 错误已印出。
//---------------------------------------------------------------------------
ERR MacrosManager::TryLocalParse( AsmLine* &Ln,
                                  Tokenfield* &LocalarguPt,
                                  Tokenfield* PreNamesSetPt )
{ LocalarguPt = NULL; // 局参指针清零。
  Tokenfield* lpt = Ln->FirstTkn();
  // lpt->Token == LOCAL ?
  if(lpt->Token != WordSToken || lpt->Name != "LOCAL")
   { return OK_no_Err; } // endif 没有找到LOCAL。

  // Yes, it is LOCAL!
  lpt->Token = LOCALTkn;
  Tokenfield* pt = lpt;       // Now, pt->next -> 第一个LOCAL标号或者NULL.
  if( !lpt->next )       // <==> lpt == NULL
   { masm.OutputErr(MissLocalIDErr); return Have_Errs; } // endif

  while( pt->next )         //   ... ',' + Word ....
   { ERR err = TokenOper::ArgvWordParser(pt); // 看它是不是一个WordList。
     if(err)
      { masm.OutputErr(err); return Have_Errs; } // endif
     // No error.
     pt = pt->next;
     // Now pt->Token == WordSToken
     if(TokenOper::HaveArguName(PreNamesSetPt, pt)) // 参数有重名!
      { masm.OutputErr(MacroArgvDupErr); return Have_Errs; } // endif
     if(TokenOper::HaveArguName(lpt, pt)) // 参数有重名!
      { masm.OutputErr(MacroArgvDupErr); return Have_Errs; } // endif
     // 至此,第一个参数OK。
     pt->Token = ArgvWordkn;    // Token 进化!
   } // end while

  LocalarguPt = lpt->next;  // 设置局参指针!
  Ln = Ln->next; // 此处修改了CLine!! 使它指向宏体头。
  return OK_no_Err;
} // end TryLocalParse
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// MroName MACRO ArgvWordkn,ArgvWordkn,ArgvWordkn...
// 对MacroDef后的形参进行语法检查。必须全部是WordSToken,不能有重名。
// 将其改成ArgvWordkn。
// 输入CLine。CLine 必须是MacroDef所在行。
// 该函数会修改CLine!!
//---------------------------------------------------------------------------
ERR MacrosManager::MacroDefParser(AsmLine* &CLine, MacroDefBody* Mbody)
{ Tokenfield* mpt = CLine->FirstTkn(); // mpt->Token == MacroDefkn。
  Tokenfield*  pt = mpt;               // mpt 指向 MACRO Name。
  ERR err;

  while( pt->next )         //   ... ',' + Word ....
   { err = TokenOper::ArgvWordParser(pt);
     if(err) { masm.OutputErr(err); return Have_Errs; } // endif
     // No error.
     pt = pt->next;
     // Now pt->Token == WordSToken
     if(TokenOper::HaveArguName(mpt, pt)) // 参数有重名!
      { masm.OutputErr(MacroArgvDupErr); return Have_Errs; } // endif
     // 至此,第一个参数OK。
     pt->Token = ArgvWordkn;    // Token 进化!
   } // end while

  Mbody->arguPtr = mpt->next;   // 设置形参指针!
  CLine = CLine->next; // 此处修改了CLine !! 使它指向宏体头。
  // CLine 不应为NULL。

  // 寻找LOCAL并进行语法分析。最后CLine指向LOCAL的下一行。
  return TryLocalParse(CLine, Mbody->localPtr, mpt);
} // end MacroDefParser
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// 登记宏体。MACRO ...... ENDM
// 输入一个汇编行,该汇编行含有一个MacroDef和一些形参。
// 把该汇编行所含的宏定义登记在宏表中。建立宏体定义。
// 它会修改CLine。通常是用masm->Ln来输入。
// 返回的CLine应该是最外层的ENDM所在的行。
//---------------------------------------------------------------------------
ERR MacrosManager::MacroRegister(AsmLine* &CLine)
{ Tokenfield* pt = CLine->FirstTkn();

  if(pt->Token != MacroDefkn)  // 在MACRO定义前面不应有标号。
   { masm.OutputErr(IllLBforMroErr); return Have_Errs; } // endif

  CLine->Enable = false; // 禁用CLine(MACRO)。

  MacroDefBody* mt = MRList->SearchMacro(pt->Name);
  if( mt )  // <==> mt != NULL,  有重名!
   { masm.OutputErr(MacroDuplicateErr); return Have_Errs; } // endif
  // 经查,没有发现重名。( mt == NULL。)

  MacroDefBody* NewMroBody = new MacroDefBody(pt->Name); // 创建新宏定义体

  // 对其后的形参进行语法检查。必须全部是WordSToken,不能有重名。
  // 如果有LOCAL,也对其后的形参进行语法检查。Token进化。
  // CLine = MacroDefkn
  if( MacroDefParser(CLine, NewMroBody) ) // 如果宏定义中有语法错误
   { delete NewMroBody; return Have_Errs; } // endif
  // 修改了CLine ~~! 也修改了NewMroBody结点的内容!!

  // 扫描宏体,识别其中的形参和局参,改成FormalArgv和LocalArgv。
  NewMroBody->MroBodyScanAndRecg(CLine); // 找出宏头。找出宏尾。
  // CLine 和 NewMroBody 都带值返回。

  // 新宏结点插入宏定义表中。
  MRList->InsertMacro(NewMroBody);
  DebugKit(printf("\nAdd macro def[%s].",(const char*)NewMroBody->MacroName););

  return OK_no_Err;
} // end MacroRegister
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// 把宏定义体中的某一行拿出来,把其中的形参用实参替代。
// 产生一个字串(len<255),返回该字串。
//---------------------------------------------------------------------------
ERR MacrosManager::MacroLineBacktoJstr(AsmLine* Line, Jstring &s)
{ s = "";
  for( Tokenfield* pt = Line->FirstTkn();
           pt;
               pt = pt->next )
   { switch(pt->Token)
     { case FormalArgv: // 形参
             { register Tokenfield* t = pt->ExpPt->ExpPt; // !!!
               if(t) { pt->Name = t->Name; } // endif
               else  { pt->Name = ""; } // endif
               break;
             } // end case
       case LocalArgv : // 局参
             { LocalArgvToJstr((int16u)pt->ExpPt->Value, pt->Name);
               break;
             } // end case
       // no default...
     } // end switch
   } // end for

  for( Tokenfield* pt = Line->FirstTkn();
           pt;
               pt = pt->next )
   { s += pt->Name;
     if(pt->next)
      { switch(pt->Token)
        { case WordSToken: case FormalArgv: case LocalArgv:
           { switch(pt->next->Token)
             { case WordSToken: case FormalArgv: case LocalArgv: case '@':
                { s = s + " "; break; } // end case
               case txtCATtxt:
                { pt = pt->next; break; } // end case
             } // end switch
             break;
           } // end case
        } // end switch
      } // endif
   } // end for

  if(s.getLen() > 255)
   { masm.OutputErr(LenExcesMroErr); return Have_Errs; } // endif
  return OK_no_Err;
} // end MacroLineBacktoJstr
//---------------------------------------------------------------------------


const MaxNest_MACRO_SUM = 99;
//---------------------------------------------------------------------------
// 宏展开词法分析器。
// 给宏定义体初始化好形参和局参后,把宏展开,并进行词法分析。
// masm->Ln受影响,Ln是宏调用所在汇编行。重要!
// 返回的err是用来送向OutputErr()的。
//---------------------------------------------------------------------------
ERR MacrosManager::MacroToToken( const MacroDefBody* mbody, // 要展开的宏定义体。
                                 AsmLine* BaseLn, // 基准行。
                                 AsmLine* InsLn,  // 插入行。
                                 AsmLine* &CLn )  // 用于返回最后展开行。
{ ERR erra = OK_no_Err;
  bool CommentEnable = false;
  AsmLine* &Ln = masm.Ln;        // Attention!!
  AsmFile* &AsmFn = masm.AsmFn;

  if(Ln->NestNo >= MaxNest_MACRO_SUM)  // 宏嵌套超过最高层数!
   { return MroCallNestOutErr; } // endif

  CLn = InsLn;    // CLn 指向宏调用所在汇编行, 它用于记录插入点。
  Jstring s;

  for( AsmLine* ln = mbody->MacroBegin;
           ln != mbody->MacroEnd;
               ln = ln->next )
   { // ..................................................................
     erra = MacroLineBacktoJstr(ln, s); // 把宏中的一行转换成字串。得到s。
     if(erra) { break; } // endif  Break from for
     DebugKit(printf("\ns=[%s]", (const char*)s); Debugkey;);

     // Now, 得到一个Strings s.
     Ln = new AsmLine;              // 创建新汇编行对象
     Ln->LineNo = BaseLn->LineNo;      // 给新行赋行号值
     Ln->NestNo = BaseLn->NestNo + 1;  //
     Ln->head->Name = s;            // 该汇编行的头结点上有展开的宏字串。

     char ts[256];
     Jassert(s.getLen()<255);

     ERR err = masm.StrLexToAsmline(s.makeStr(ts), Ln, CommentEnable);
     // 把一行转换成Token流。
     if(err == 1) { erra = Have_Errs; } // endif
     // err maybe == 2 or 0.

     if(Ln->TknLNotEmpty()) // 如果不是只有一个头结点的话
      { AsmFn->InsertAsmLine(Ln, CLn); // 在CLn后插入。
        CLn = Ln;                   // 更新CLn的值。
      } // endif // 汇编行加进AsmFile中。
     else                   // 只有一个头结点的汇编行不添加到AsmFile中.
      { delete Ln; Ln = NULL; } // end else
     // ..................................................................
   } // end for

  Ln = InsLn;       // 重置Ln。
  return erra;
} // end MacroToToken
//---------------------------------------------------------------------------

const int16u MaxMroCallSum = 60000;
//---------------------------------------------------------------------------
// 宏调用处理。处理宏替代。
// Ln受影响。Ln为宏调用所在汇编行。
//---------------------------------------------------------------------------
ERR MacrosManager::MacroCall(AsmLine* &Ln)
{ if(++MacroCallCounter > MaxMroCallSum)
   { FatalErr("\nMacro calling nested too deep or too many macros!"); } // endif

  Tokenfield* pt = Ln->FirstTkn();     // pt->Token should be MacroRefkn.
  for( ; pt && pt->Token != MacroRefkn; pt = pt->next ); // end for

  Tokenfield* MDefPt = pt;   // 保存宏调用结点指针。
  MacroDefBody* mbody = pt->MacroPt; // 得到该宏对应的宏定义体。

  // 把实参代入形参。实参个数可能少于形参个数。
  pt = pt->next; // Now, pt->Token should be MroParamtn.
  register Tokenfield* gt = mbody->arguPtr;
  for( ; gt && pt; gt = gt->next, pt = pt->next )
   { //..................................................
     Assert( if(pt->Token != MroParamtn)          // Just for debug!!
              { printf("\nBugs in MacroCall!"); Debugkey; } // endif
            );
     //..................................................
     gt->ExpPt = pt; // 宏定义体中的形参指针指向实参Token!!
   } // end for
  if( gt ) // 实参个数少于形参个数。
   { masm.OutWarning(InsufParaMroWarn);
     for( ; gt; gt = gt->next) // 给每个未赋值的形参赋NUL。
      { gt->ExpPt = NULL; } // end for
   } // endif

  // 给局参赋值。
  for( gt = mbody->localPtr; gt; gt = gt->next )
   { gt->Value = AssaignLocalLabelNo(); } // end for

  // 给宏定义体初始化好形参和局参后,送宏展开,词法分析器。
  AsmLine* LastLn;
  ERR err = MacroToToken(mbody,Ln,Ln,LastLn);
  if(err) { masm.OutputErr(MacroLexErr); return err; } // endif

  // Now, Ln仍然为宏调用所在汇编行。
  TokenOper::DelTokenList(MDefPt->next);  // 宏完全展开后,把宏调用之后指令删除。
  MDefPt->Token = MroCalling;  // Token进化!

  return err;
} // end MacroCall
//---------------------------------------------------------------------------
#undef FatalErrPrn
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// REPT 语法分析器。
// 它返回REPT重复的次数。
//---------------------------------------------------------------------------
int16u MacrosManager::REPT_Parser(ERR &err, AsmLine* Ln)
{ err = OK_no_Err;
  Tokenfield* pt = Ln->head;
  for( ; pt && pt->Token != REPTTkn; pt = pt->next ); // end for
  // Now, pt == REPTTkn or NULL
  // pt->next should be a Expr. or NULL.
  // Need Only One Expr
  int8 count = TokenOper::CalExpNum(pt, err);
  if(err) { return 0; } // endif
  switch(count)
  { case 0 : { err = ArguInsufErr; return 0; } // end case
    case 1 : { break; } // end case
    default: { err = ArguInsufErr; return 0; } // end case
  } // end switch

  // Now, pt 指向REPT Token。
  const TriVal* trv
       = masm.LabMger->CalExpression(err,pt->next->ExpPt); // 带回err。
  if(err)    { err = BadExptReptErr; return 0; } // 该行异常终止

  // No error.
  pt->Token = ReptDefkn; // Token进化!!
  pt->Value = trv->val;  // 该结果暂存在REPT Token的Value域中。

  // 得到了一个数值。检查数值范围。(0 ~ 65535)

⌨️ 快捷键说明

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