diff --git a/compiler/scasm/amx_compiler.cpp b/compiler/scasm/amx_compiler.cpp index 063846d5..119a7efd 100755 --- a/compiler/scasm/amx_compiler.cpp +++ b/compiler/scasm/amx_compiler.cpp @@ -29,6 +29,8 @@ Compiler::Compiler() Output = 0; stacksize = cellsize * 4096; debug = false; + pack = false; + dopt = false; Init(); } @@ -53,9 +55,20 @@ Compiler::Compiler(std::string &f) filename.assign(f); stacksize = cellsize * 4096; debug = false; + pack = false; + dopt = false; Init(); } +bool Compiler::SetDOpt() +{ + bool state = dopt; + + dopt = dopt ? false : true; + + return state; +} + bool Compiler::SetDebug() { bool state = debug; @@ -65,6 +78,15 @@ bool Compiler::SetDebug() return state; } +bool Compiler::SetPack() +{ + bool state = pack; + + pack = pack ? false : true; + + return state; +} + void Compiler::Load(std::string &f) { filename.assign(f); @@ -111,6 +133,49 @@ int Compiler::CipCount() return cipc; } +void Compiler::WriteCell(FILE *fp, ucell *c, int repeat) +{ + unsigned char T[5] = {0,0,0,0,0}; + unsigned char code = 0; + int index = 0; + ucell p = (*c); + int i = 0; + + for (i=1; i<=repeat; i++) + { + if (pack) + { + for (index=0;index<5;index++) + { + T[index]=(unsigned char)(p & 0x7f); + p>>=7; + } + while (index>1 && T[index-1]==0 && (T[index-2] & 0x40)==0) + { + index--; + } + if (index==5 && T[index-1]==0x0f && (T[index-2] & 0x40)!=0) + { + index--; + } + while (index>1 && T[index-1]==0x7f && (T[index-2] & 0x40)!=0) + { + index--; + } + assert(index>0); + while (index-->0) + { + code=(unsigned char)((index==0)?T[index]:(T[index]|0x80)); + fwrite((void*)&code, sizeof(unsigned char), 1, fp); + bitsOut += sizeof(unsigned char); + } + } else { + fwrite((void*)c, sizeof(ucell), 1, fp); + bitsOut += sizeof(ucell); + } + } +} + bool Compiler::Compile(std::string &out) { if (CodeList.size() < 1 || !CError || CError->GetStatus() >= Err_Error) @@ -118,6 +183,7 @@ bool Compiler::Compile(std::string &out) return false; } + bitsOut = 0; int32_t fileSize = 0; int16_t magic = (int16_t)AMX_MAGIC; char file_version = CUR_FILE_VERSION; @@ -127,6 +193,15 @@ bool Compiler::Compile(std::string &out) int32_t cod, dat, hea, stp, cip, publics, natives, libraries; int32_t pubvars, tags, names; int hdrEnd = sizeof(AMX_HEADER); + + if (debug) + { + flags |= AMX_FLAG_DEBUG; + } + if (pack) + { + flags |= AMX_FLAG_COMPACT; + } std::vector ProcList; std::vector::iterator pl; @@ -195,6 +270,7 @@ bool Compiler::Compile(std::string &out) cOffset += (int)strlen(Nametbl.at(off).Name) + 1; } + bitsOut = cOffset; cod = cOffset; dat = cod + CipCount(); hea = dat + DAT->GetSize(); @@ -267,15 +343,15 @@ bool Compiler::Compile(std::string &out) std::vector::iterator ci; std::vector::iterator di; - int cop = 0; + ucell cop = 0; for (ci = CodeList.begin(); ci != CodeList.end(); ci++) { cop = (*ci)->op; - fwrite((void *)&cop, sizeof(int32_t), 1, fp); + WriteCell(fp, &cop, 1); for (di = (*ci)->params.begin(); di != (*ci)->params.end(); di++) { cop = (*di); - fwrite((void *)&cop, sizeof(int32_t), 1, fp); + WriteCell(fp, &cop, 1); } } @@ -283,7 +359,7 @@ bool Compiler::Compile(std::string &out) std::vector::iterator dmi; DAT->GetData(dm); - int val = 0; + ucell val = 0; const char *s = 0; for (dmi = dm.begin(); dmi != dm.end(); dmi++) { @@ -298,18 +374,25 @@ bool Compiler::Compile(std::string &out) for (int q = 0; q < (*dmi)->e.Size(); q++) { val = s[q]; - fwrite((void*)&val, sizeof(int32_t), 1, fp); + WriteCell(fp, &val, 1); } } } else { - char c = (*dmi)->fill; - for (int iter=0; iter<=(*dmi)->e.GetNumber(); iter++) - { - fwrite((void*)&c, sizeof(int32_t), 1, fp); - } + if (DAT->IsOptimized()) + break; + ucell c = (*dmi)->fill; + WriteCell(fp, &c, (*dmi)->e.GetNumber()); } } + /* Was packing enabled? Re-output the actual size */ + if (pack) + { + fseek(fp, 0, SEEK_SET); + fwrite((void *)&bitsOut, sizeof(int32_t), 1, fp); + fseek(fp, 0, SEEK_END); + } + fclose(fp); return true; @@ -326,32 +409,44 @@ void Compiler::Clear() CSymbols->Clear(); } +/* Two pass parser. + * The first pass applies macros + defines + directives + * natives, and data. + * The second pass eats up everything else (code, publics) + */ bool Compiler::Parse() { - std::ifstream fp(filename.c_str()); + FILE *fp = 0; char buffer[256] = {0}; std::stack DefStack; std::stack LabelStack; curLine = 0; AsmSection sec = Asm_None; lastCip = 0-cellsize; + int pass = 0; - if (!fp.is_open()) +Start: + fp = fopen(filename.c_str(), "rt"); + curLine = 0; + sec = Asm_None; + lastCip = 0-cellsize; + + if (!fp) { CError->ErrorMsg(Err_FileOpen, filename.c_str()); return false; } - while (!fp.eof()) + while (!feof(fp)) { - fp.getline(buffer, 255); + fgets(buffer, 255, fp); curLine+=1; /* Check for preprocessor directives */ if (buffer[0] == '#') { std::string procline(buffer); - if (procline.substr(0, 3).compare("#if") == 0) + if (procline.substr(0, 6).compare("#ifdef") == 0) { std::string def; std::string temp; @@ -359,16 +454,37 @@ bool Compiler::Parse() StringBreak(procline, def, temp); StringBreak(temp, def, comp); DefineMngr::Define *D = 0; - if ((D = CDefines->FindDefine(def)) == 0) + if ( (D = CDefines->FindDefine(def)) == NULL) { DefStack.push(0); - } else if (D->GetDefine()->compare(comp) == 0) { + } else { + if (D->GetDefine()->compare("0") == 0) + { + DefStack.push(0); + } else { + DefStack.push(1); + } + } + } else if (procline.substr(0, 7).compare("#ifndef") == 0) { + std::string def; + std::string temp; + std::string comp; + StringBreak(procline, def, temp); + StringBreak(temp, def, comp); + DefineMngr::Define *D = 0; + if ( (D = CDefines->FindDefine(def)) == NULL) + { DefStack.push(1); } else { - DefStack.push(0); + if (D->GetDefine()->compare("0") == 0) + { + DefStack.push(1); + } else { + DefStack.push(0); + } } } else if (procline.substr(0, 5).compare("#else") == 0) { - if (DefStack.size()) + if (!DefStack.empty()) { if (DefStack.top() == 1) { @@ -383,7 +499,7 @@ bool Compiler::Parse() } continue; } else if (procline.substr(0, 6).compare("#endif") == 0) { - if (DefStack.size()) + if (!DefStack.empty()) { DefStack.pop(); } else { @@ -399,7 +515,11 @@ bool Compiler::Parse() continue; } } - ProcessDirective(procline); + // only process directives on pass one + if (pass == 0) + { + ProcessDirective(procline); + } } continue; } @@ -428,7 +548,7 @@ bool Compiler::Parse() if (line.compare(".DATA") == 0) { sec = Asm_Data; - } else if (line.compare(".CODE") == 0) { + } else if (line.compare(".CODE") == 0) {; sec = Asm_Code; } else if (line.compare(".PUBLIC") == 0) { sec = Asm_Public; @@ -438,13 +558,16 @@ bool Compiler::Parse() sec = Asm_Invalid; CError->ErrorMsg(Err_Invalid_Section, buffer); } - /* Update the labels */ - CLabels->CompleteQueue(true); - while (!LabelStack.empty()) + if (pass == 1) { - CLabels->EraseLabel(LabelStack.top()); - CSymbols->EraseSymbol(LabelStack.top()); - LabelStack.pop(); + /* Update the labels */ + CLabels->CompleteQueue(true); + while (!LabelStack.empty()) + { + CLabels->EraseLabel(LabelStack.top()); + CSymbols->EraseSymbol(LabelStack.top()); + LabelStack.pop(); + } } } else { /* Do pre-processing */ @@ -461,6 +584,8 @@ bool Compiler::Parse() } else if (sec == Asm_Invalid) { /* Just ignore it */ } else if (sec == Asm_Data) { + if (pass == 1) + continue; /* Format is Symbol, [db|stat], Data */ std::string symbol; std::string data; @@ -505,17 +630,17 @@ bool Compiler::Parse() CExpr t(CError); t.Set(fill); t.Evaluate(); - e.Set(amt); - e.Evaluate(); + e = EvalE(amt, Sym_None); DAT->Add(symbol, e, false, t.GetNumber()); } else { - e.Set(data); - e.Evaluate(); + e = EvalE(data, Sym_None); DAT->Add(symbol, e, false, 0); } } CSymbols->AddSymbol(symbol, Sym_Dat, CurLine()); } else if (sec == Asm_Public) { + if (pass == 0) + continue; if (!IsValidSymbol(line)) { CError->ErrorMsg(Err_Invalid_Symbol); @@ -538,6 +663,8 @@ bool Compiler::Parse() continue; } } else if (sec == Asm_Native) { + if (pass == 1) + continue; if (!IsValidSymbol(line)) { CError->ErrorMsg(Err_Invalid_Symbol); @@ -552,6 +679,8 @@ bool Compiler::Parse() S = CSymbols->AddSymbol(line, Sym_Native, CurLine()); CNatives->AddNative(S); } else if (sec == Asm_Code) { + if (pass == 0) + continue; std::string code; std::string params; SymbolList::Symbol *S; @@ -1454,12 +1583,25 @@ bool Compiler::Parse() } /* Line processing */ } /* While */ + // go for second pass + if (pass == 0) + { + pass = 1; + fclose(fp); + if (dopt) + DAT->Optimize(); + goto Start; + } + /* We're not done! Check the label Queue */ CLabels->CompleteQueue(); CError->PrintReport(); + if (CError->GetStatus() >= Err_Error) + { return false; + } return true; } @@ -1882,13 +2024,22 @@ void Compiler::ProcessDirective(std::string &text) } } +int Compiler::Eval(std::string &str, SymbolType sym) +{ + CExpr e(CError); + + e = EvalE(str, sym); + + return e.GetNumber(); +} + /* The evaluator works by storing expressions on a stack. Each expression is an RPN-ordered pair of lists for ops and values Every time the stack is popped, the expression is evaluated by searching for the highest operators and evaluating them. Note that string literals are not allowed here yet. */ -int Compiler::Eval(std::string &str, SymbolType sym) +CExpr Compiler::EvalE(std::string &str, SymbolType sym) { std::stack Stack; std::string bpstr; @@ -2025,7 +2176,7 @@ int Compiler::Eval(std::string &str, SymbolType sym) delete r; r = 0; - return final.GetNumber(); + return final; } CExpr Compiler::EvalRpn(rpn *r, SymbolType sym) diff --git a/compiler/scasm/amx_compiler.h b/compiler/scasm/amx_compiler.h index 734f6a0b..388d1ab5 100755 --- a/compiler/scasm/amx_compiler.h +++ b/compiler/scasm/amx_compiler.h @@ -68,16 +68,20 @@ public: int CurCip() { return lastCip; } Asm *CurAsm() { return curAsm; } bool SetDebug(); -public: //private + bool SetPack(); + bool SetDOpt(); int DerefSymbol(std::string &str, SymbolType sym = Sym_None); + bool IsSymbol(std::string &str); +private: void ProcessDirective(std::string &text); void Init(); void InitOpcodes(); int Eval(std::string &str, SymbolType sym = Sym_None); + CExpr EvalE(std::string &str, SymbolType sym = Sym_None); CExpr EvalRpn(rpn *r, SymbolType sym); OpToken OperToken(char c); char OperChar(OpToken c); - bool IsSymbol(std::string &str); + void WriteCell(FILE *fp, ucell *c, int repeat); private: std::vector CodeList; std::map OpCodes; @@ -96,6 +100,9 @@ private: int cellsize; int stacksize; bool debug; + bool pack; + bool dopt; + int bitsOut; Asm *curAsm; }; diff --git a/compiler/scasm/amx_data.cpp b/compiler/scasm/amx_data.cpp index 32f17744..0137ef6c 100755 --- a/compiler/scasm/amx_data.cpp +++ b/compiler/scasm/amx_data.cpp @@ -45,6 +45,7 @@ DataMngr::Datum::Datum() db = false; offset = -1; fill = 0; + zeroed = false; } void DataMngr::Add(std::string &s, CExpr &expr, bool db, int fill) @@ -128,3 +129,68 @@ void DataMngr::GetData(std::vector &dList) } } +void DataMngr::PrintTable() +{ + std::vector::iterator i; + DataMngr::Datum *p = 0; + + printf("Symbol\tSize\n"); + for (i=List.begin(); i!=List.end(); i++) + { + p = (*i); + printf("%s\t%d\n", p->symbol.c_str(), p->offset); + } +} + +//Rewrite the DAT section so empties are at the end +void DataMngr::Optimize() +{ + std::vector DbList; + std::vector MtList; + std::vector::iterator i; + + for (i=List.begin(); i!=List.end(); i++) + { + if ( (*i)->db ) + { + DbList.push_back( (*i) ); + } else if ( (*i)->fill == 0 ) { + MtList.push_back( (*i) ); + } else { + DbList.push_back( (*i) ); + } + } + + List.clear(); + + lastOffset = 0; + cursize = 0; + int size = 0; + + for (i=DbList.begin(); i!=DbList.end(); i++) + { + size = (( (*i)->e.GetType() == Val_Number + || (*i)->e.GetType() == Val_Float ) ? + cellsize : (*i)->e.Size() * cellsize); + (*i)->offset = lastOffset; + lastOffset += size; + (*i)->zeroed = false; + List.push_back( (*i) ); + } + + cursize = lastOffset; + DbList.clear(); + + for (i=MtList.begin(); i!=MtList.end(); i++) + { + size = ( (*i)->e.GetNumber() * cellsize ); + (*i)->offset = lastOffset; + lastOffset += size; + (*i)->zeroed = true; + List.push_back( (*i) ); + } + + MtList.clear(); + + optimized = true; +} diff --git a/compiler/scasm/amx_data.h b/compiler/scasm/amx_data.h index fec1088c..7aa0a9d0 100755 --- a/compiler/scasm/amx_data.h +++ b/compiler/scasm/amx_data.h @@ -35,22 +35,27 @@ public: bool db; int offset; int fill; + bool zeroed; }; public: ~DataMngr(); - DataMngr() { cellsize = 4; lastOffset = 0; cursize = 0; } - DataMngr(int cell) { lastOffset = 0; cellsize = cell; cursize = 0; } + DataMngr() { cellsize = 4; lastOffset = 0; cursize = 0; optimized = false; } + DataMngr(int cell) { lastOffset = 0; cellsize = cell; cursize = 0; optimized = false; } void Add(std::string &s, CExpr &expr, bool db = false, int fill = 0); DataMngr::Datum *FindData(std::string &sym); void GetData(std::vector &dList); int GetOffset(std::string &sym); int GetSize(); void Clear(); + void PrintTable(); + void Optimize(); + bool IsOptimized() { return optimized; } private: std::vector List; int lastOffset; int cellsize; int cursize; + bool optimized; public: static const int nof = -1; }; diff --git a/compiler/scasm/amxasm.cpp b/compiler/scasm/amxasm.cpp index 1650d34b..1b7433ae 100755 --- a/compiler/scasm/amxasm.cpp +++ b/compiler/scasm/amxasm.cpp @@ -24,11 +24,10 @@ std::string filename; std::string output_name; +Compiler Program; int main(int argc, char **argv) -{ - Compiler Program; - +{ get_options(argc, argv, Program); if (filename.size() < 1) @@ -76,6 +75,12 @@ void get_options(int argc, char **argv, Compiler &Prog) } break; } + case 'c': + { + Program.SetPack(); + opt_flag = 0; + break; + } case 'v': { opt_flag = 0; /* no options expected */ @@ -89,6 +94,18 @@ void get_options(int argc, char **argv, Compiler &Prog) Prog.SetDebug(); break; } + case 'h': + { + opt_flag = 0; + Prog.SetDOpt(); + break; + } + case 'f': + { + opt_flag = 0; + Prog.SetDOpt(); + Prog.SetPack(); + } } /* switch */ } else { /* - */ if (!opt_flag) @@ -110,7 +127,7 @@ void get_options(int argc, char **argv, Compiler &Prog) void print_version() { - printf("Small/AMX Assembler 1.00\n"); + printf("Small/AMX Assembler 1.01\n"); printf("(C)2004 David 'BAILOPAN' Anderson\n"); } @@ -120,5 +137,8 @@ void print_options() printf("\t-d\t\t- Add debug opcodes (will double file size)\n"); printf("\t-v\t\t- Output version and exit\n"); printf("\t-o\t\t- Specify file to write\n"); + printf("\t-c\t\t- Enable compact encoding\n"); + printf("\t-h\t\t- Optimize DAT section\n"); + printf("\t-f\t\t- Optimal Build\n"); printf("\n"); }