ReactOS 0.4.17-dev-1196-gb6224c3
asmpp.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS host tools
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: ASM preprocessor
5 * COPYRIGHT: Copyright 2021 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8// Optimize even on debug builds, because otherwise it's ridiculously slow
9#ifdef _MSC_VER
10#pragma optimize("gst", on)
11#pragma auto_inline(on)
12#else
13#pragma GCC optimize("O3,inline")
14#endif
15
16#include "tokenizer.hpp"
17#include <cstdlib>
18#include <cstdio>
19#include <sstream>
20#include <ctime>
21#include <cstring>
22
23#ifndef _WIN32
24#define _stricmp strcasecmp
25#endif
26
27#define PROFILING_ENABLED 0
28
29using namespace std;
30
32
34{
35 Invalid = -1,
43
51
68
72
84
87
101
105
106int fake_printf(const char* format, ...)
107{
108 return 0;
109}
110
111//#define printf fake_printf
112
113// Use a look-ahead for following characters, not included into the match
114//#define FOLLOWED_BY(x) R"((?=)" x R"())"
115#define FOLLOWED_BY(x) x
116
117#define ANY_CHAR R"((?:.|\n))"
118#define WHITESPACE R"((?:[ \t]++))"
119#define NEWLINE R"([\n])"
120#define WS_OR_NL R"((?:)" WHITESPACE "|" NEWLINE R"()+)"
121#define SEPARATOR R"([\s,\=\+\-\*\/\:\~\[\]])"
122
123#define INST_PREFIX \
124 "REX|REXW|REXR|REXX|REXB|LOCK|REP|REPE|REPZ|REPNE|REPNZ"
125
126#define INSTRUCTION \
127 "AAA|AAD|AAM|AAS|ADC|ADCX|ADD|ADDPD|ADDPS|ADDSD|ADDSS|ADDSUBPD|ADDSUBPS|" \
128 "ADOX|AESDEC|AESDECLAST|AESENC|AESENCLAST|AESIMC|AESKEYGENASSIST|AND|ANDN|" \
129 "ANDNPD|ANDNPS|ANDPD|ANDPS|ARPL|BEXTR|BLENDPD|BLENDPS|BLENDVPD|BLENDVPS|" \
130 "BLSI|BLSMSK|BLSR|BNDCL|BNDCN|BNDCU|BNDLDX|BNDMK|BNDMOV|BNDSTX|BOUND|BSF|" \
131 "BSR|BSWAP|BT|BTC|BTR|BTS|BZHI|CALL|CBW|CDQ|CDQE|CLAC|CLC|CLD|CLDEMOTE|" \
132 "CLFLUSH|CLFLUSHOPT|CLI|CLTS|CLWB|CMC|CMOVcc|CMP|CMPPD|CMPPS|CMPS|CMPSB|" \
133 "CMPSD|CMPSQ|CMPSS|CMPSW|CMPXCHG|CMPXCHG16B|CMPXCHG8B|COMISD|COMISS|CPUID|" \
134 "CQO|CRC32|CVTDQ2PD|CVTDQ2PS|CVTPD2DQ|CVTPD2PI|CVTPD2PS|CVTPI2PD|CVTPI2PS|" \
135 "CVTPS2DQ|CVTPS2PD|CVTPS2PI|CVTSD2SI|CVTSD2SS|CVTSI2SD|CVTSI2SS|CVTSS2SD|" \
136 "CVTSS2SI|CVTTPD2DQ|CVTTPD2PI|CVTTPS2DQ|CVTTPS2PI|CVTTSD2SI|CVTTSS2SI|CWD|" \
137 "CWDE|DAA|DAS|DEC|DIV|DIVPD|DIVPS|DIVSD|DIVSS|DPPD|DPPS|EMMS|ENTER|" \
138 "EXTRACTPS|F2XM1|FABS|FADD|FADDP|FBLD|FBSTP|FCHS|FCLEX|FCMOVcc|FCOM|FCOMI|" \
139 "FCOMIP|FCOMP|FCOMPP|FCOS|FDECSTP|FDIV|FDIVP|FDIVR|FDIVRP|FFREE|FIADD|" \
140 "FICOM|FICOMP|FIDIV|FIDIVR|FILD|FIMUL|FINCSTP|FINIT|FIST|FISTP|FISTTP|" \
141 "FISUB|FISUBR|FLD|FLD1|FLDCW|FLDENV|FLDL2E|FLDL2T|FLDLG2|FLDLN2|FLDPI|" \
142 "FLDZ|FMUL|FMULP|FNCLEX|FNINIT|FNOP|FNSAVE|FNSTCW|FNSTENV|FNSTSW|FPATAN|" \
143 "FPREM|FPREM1|FPTAN|FRNDINT|FRSTOR|FSAVE|FSCALE|FSIN|FSINCOS|FSQRT|FST|" \
144 "FSTCW|FSTENV|FSTP|FSTSW|FSUB|FSUBP|FSUBR|FSUBRP|FTST|FUCOM|FUCOMI|" \
145 "FUCOMIP|FUCOMP|FUCOMPP|FWAIT|FXAM|FXCH|FXRSTOR|FXSAVE|FXTRACT|FYL2X|" \
146 "FYL2XP1|GF2P8AFFINEINVQB|GF2P8AFFINEQB|GF2P8MULB|HADDPD|HADDPS|HLT|" \
147 "HSUBPD|HSUBPS|IDIV|IMUL|IN|INC|INS|INSB|INSD|INSERTPS|INSW|INT|INT1|INT3|" \
148 "INTO|INVD|INVLPG|INVPCID|IRET|IRETD|JMP|Jcc|KADDB|KADDD|KADDQ|KADDW|" \
149 "KANDB|KANDD|KANDNB|KANDND|KANDNQ|KANDNW|KANDQ|KANDW|KMOVB|KMOVD|KMOVQ|" \
150 "KMOVW|KNOTB|KNOTD|KNOTQ|KNOTW|KORB|KORD|KORQ|KORTESTB|KORTESTD|KORTESTQ|" \
151 "KORTESTW|KORW|KSHIFTLB|KSHIFTLD|KSHIFTLQ|KSHIFTLW|KSHIFTRB|KSHIFTRD|" \
152 "KSHIFTRQ|KSHIFTRW|KTESTB|KTESTD|KTESTQ|KTESTW|KUNPCKBW|KUNPCKDQ|KUNPCKWD|" \
153 "KXNORB|KXNORD|KXNORQ|KXNORW|KXORB|KXORD|KXORQ|KXORW|LAHF|LAR|LDDQU|" \
154 "LDMXCSR|LDS|LEA|LEAVE|LES|LFENCE|LFS|LGDT|LGS|LIDT|LLDT|LMSW|LODS|" \
155 "LODSB|LODSD|LODSQ|LODSW|LOOP|LOOPcc|LSL|LSS|LTR|LZCNT|MASKMOVDQU|MASKMOVQ|" \
156 "MAXPD|MAXPS|MAXSD|MAXSS|MFENCE|MINPD|MINPS|MINSD|MINSS|MONITOR|MOV|MOVAPD|" \
157 "MOVAPS|MOVBE|MOVD|MOVDDUP|MOVDIR64B|MOVDIRI|MOVDQ2Q|MOVDQA|MOVDQU|MOVHLPS|" \
158 "MOVHPD|MOVHPS|MOVLHPS|MOVLPD|MOVLPS|MOVMSKPD|MOVMSKPS|MOVNTDQ|MOVNTDQA|" \
159 "MOVNTI|MOVNTPD|MOVNTPS|MOVNTQ|MOVQ|MOVQ2DQ|MOVS|MOVSB|MOVSD|MOVSHDUP|" \
160 "MOVSLDUP|MOVSQ|MOVSS|MOVSW|MOVSX|MOVSXD|MOVUPD|MOVUPS|MOVZX|MPSADBW|MUL|" \
161 "MULPD|MULPS|MULSD|MULSS|MULX|MWAIT|NEG|NOP|NOT|OR|ORPD|ORPS|OUT|OUTS|" \
162 "OUTSB|OUTSD|OUTSW|PABSB|PABSD|PABSQ|PABSW|PACKSSDW|PACKSSWB|PACKUSDW|" \
163 "PACKUSWB|PADDB|PADDD|PADDQ|PADDSB|PADDSW|PADDUSB|PADDUSW|PADDW|PALIGNR|" \
164 "PAND|PANDN|PAUSE|PAVGB|PAVGW|PBLENDVB|PBLENDW|PCLMULQDQ|PCMPEQB|PCMPEQD|" \
165 "PCMPEQQ|PCMPEQW|PCMPESTRI|PCMPESTRM|PCMPGTB|PCMPGTD|PCMPGTQ|PCMPGTW|" \
166 "PCMPISTRI|PCMPISTRM|PDEP|PEXT|PEXTRB|PEXTRD|PEXTRQ|PEXTRW|PHADDD|PHADDSW|" \
167 "PHADDW|PHMINPOSUW|PHSUBD|PHSUBSW|PHSUBW|PINSRB|PINSRD|PINSRQ|PINSRW|" \
168 "PMADDUBSW|PMADDWD|PMAXSB|PMAXSD|PMAXSQ|PMAXSW|PMAXUB|PMAXUD|PMAXUQ|PMAXUW|" \
169 "PMINSB|PMINSD|PMINSQ|PMINSW|PMINUB|PMINUD|PMINUQ|PMINUW|PMOVMSKB|PMOVSX|" \
170 "PMOVZX|PMULDQ|PMULHRSW|PMULHUW|PMULHW|PMULLD|PMULLQ|PMULLW|PMULUDQ|POP|" \
171 "POPA|POPAD|POPCNT|POPF|POPFD|POPFQ|POR|PREFETCHW|PREFETCHh|PSADBW|PSHUFB|" \
172 "PSHUFD|PSHUFHW|PSHUFLW|PSHUFW|PSIGNB|PSIGND|PSIGNW|PSLLD|PSLLDQ|PSLLQ|" \
173 "PSLLW|PSRAD|PSRAQ|PSRAW|PSRLD|PSRLDQ|PSRLQ|PSRLW|PSUBB|PSUBD|PSUBQ|PSUBSB|" \
174 "PSUBSW|PSUBUSB|PSUBUSW|PSUBW|PTEST|PTWRITE|PUNPCKHBW|PUNPCKHDQ|PUNPCKHQDQ|" \
175 "PUNPCKHWD|PUNPCKLBW|PUNPCKLDQ|PUNPCKLQDQ|PUNPCKLWD|PUSH|PUSHA|PUSHAD|" \
176 "PUSHF|PUSHFD|PUSHFQ|PXOR|RCL|RCPPS|RCPSS|RCR|RDFSBASE|RDGSBASE|RDMSR|" \
177 "RDPID|RDPKRU|RDPMC|RDRAND|RDSEED|RDTSC|RDTSCP|" \
178 "RET|ROL|ROR|RORX|ROUNDPD|ROUNDPS|ROUNDSD|ROUNDSS|RSM|RSQRTPS|RSQRTSS|SAHF|" \
179 "SAL|SAR|SARX|SBB|SCAS|SCASB|SCASD|SCASW|SETcc|SFENCE|SGDT|SHA1MSG1|" \
180 "SHA1MSG2|SHA1NEXTE|SHA1RNDS4|SHA256MSG1|SHA256MSG2|SHA256RNDS2|SHL|SHLD|" \
181 "SHLX|SHR|SHRD|SHRX|SHUFPD|SHUFPS|SIDT|SLDT|SMSW|SQRTPD|SQRTPS|SQRTSD|" \
182 "SQRTSS|STAC|STC|STD|STI|STMXCSR|STOS|STOSB|STOSD|STOSQ|STOSW|STR|SUB|" \
183 "SUBPD|SUBPS|SUBSD|SUBSS|SWAPGS|SYSCALL|SYSENTER|SYSEXIT|SYSRET|TEST|" \
184 "TPAUSE|TZCNT|UCOMISD|UCOMISS|UD|UMONITOR|UMWAIT|UNPCKHPD|UNPCKHPS|" \
185 "UNPCKLPD|UNPCKLPS|VALIGND|VALIGNQ|VBLENDMPD|VBLENDMPS|VBROADCAST|" \
186 "VCOMPRESSPD|VCOMPRESSPS|VCVTPD2QQ|VCVTPD2UDQ|VCVTPD2UQQ|VCVTPH2PS|" \
187 "VCVTPS2PH|VCVTPS2QQ|VCVTPS2UDQ|VCVTPS2UQQ|VCVTQQ2PD|VCVTQQ2PS|VCVTSD2USI|" \
188 "VCVTSS2USI|VCVTTPD2QQ|VCVTTPD2UDQ|VCVTTPD2UQQ|VCVTTPS2QQ|VCVTTPS2UDQ|" \
189 "VCVTTPS2UQQ|VCVTTSD2USI|VCVTTSS2USI|VCVTUDQ2PD|VCVTUDQ2PS|VCVTUQQ2PD|" \
190 "VCVTUQQ2PS|VCVTUSI2SD|VCVTUSI2SS|VDBPSADBW|VERR|VERW|VEXPANDPD|VEXPANDPS|" \
191 "VEXTRACTF128|VEXTRACTF32x4|VEXTRACTF32x8|VEXTRACTF64x2|VEXTRACTF64x4|" \
192 "VEXTRACTI128|VEXTRACTI32x4|VEXTRACTI32x8|VEXTRACTI64x2|VEXTRACTI64x4|" \
193 "VFIXUPIMMPD|VFIXUPIMMPS|VFIXUPIMMSD|VFIXUPIMMSS|VFMADD132PD|VFMADD132PS|" \
194 "VFMADD132SD|VFMADD132SS|VFMADD213PD|VFMADD213PS|VFMADD213SD|VFMADD213SS|" \
195 "VFMADD231PD|VFMADD231PS|VFMADD231SD|VFMADD231SS|VFMADDSUB132PD|" \
196 "VFMADDSUB132PS|VFMADDSUB213PD|VFMADDSUB213PS|VFMADDSUB231PD|" \
197 "VFMADDSUB231PS|VFMSUB132PD|VFMSUB132PS|VFMSUB132SD|VFMSUB132SS|" \
198 "VFMSUB213PD|VFMSUB213PS|VFMSUB213SD|VFMSUB213SS|VFMSUB231PD|VFMSUB231PS|" \
199 "VFMSUB231SD|VFMSUB231SS|VFMSUBADD132PD|VFMSUBADD132PS|VFMSUBADD213PD|" \
200 "VFMSUBADD213PS|VFMSUBADD231PD|VFMSUBADD231PS|VFNMADD132PD|VFNMADD132PS|" \
201 "VFNMADD132SD|VFNMADD132SS|VFNMADD213PD|VFNMADD213PS|VFNMADD213SD|" \
202 "VFNMADD213SS|VFNMADD231PD|VFNMADD231PS|VFNMADD231SD|VFNMADD231SS|" \
203 "VFNMSUB132PD|VFNMSUB132PS|VFNMSUB132SD|VFNMSUB132SS|VFNMSUB213PD|" \
204 "VFNMSUB213PS|VFNMSUB213SD|VFNMSUB213SS|VFNMSUB231PD|VFNMSUB231PS|" \
205 "VFNMSUB231SD|VFNMSUB231SS|VFPCLASSPD|VFPCLASSPS|VFPCLASSSD|VFPCLASSSS|" \
206 "VGATHERDPD|VGATHERDPS|VGATHERQPD|VGATHERQPS|VGETEXPPD|VGETEXPPS|VGETEXPSD|" \
207 "VGETEXPSS|VGETMANTPD|VGETMANTPS|VGETMANTSD|VGETMANTSS|VINSERTF128|" \
208 "VINSERTF32x4|VINSERTF32x8|VINSERTF64x2|VINSERTF64x4|VINSERTI128|" \
209 "VINSERTI32x4|VINSERTI32x8|VINSERTI64x2|VINSERTI64x4|VMASKMOV|VMOVDQA32|" \
210 "VMOVDQA64|VMOVDQU16|VMOVDQU32|VMOVDQU64|VMOVDQU8|VPBLENDD|VPBLENDMB|" \
211 "VPBLENDMD|VPBLENDMQ|VPBLENDMW|VPBROADCAST|VPBROADCASTB|VPBROADCASTD|" \
212 "VPBROADCASTM|VPBROADCASTQ|VPBROADCASTW|VPCMPB|VPCMPD|VPCMPQ|VPCMPUB|" \
213 "VPCMPUD|VPCMPUQ|VPCMPUW|VPCMPW|VPCOMPRESSD|VPCOMPRESSQ|VPCONFLICTD|" \
214 "VPCONFLICTQ|VPERM2F128|VPERM2I128|VPERMB|VPERMD|VPERMI2B|VPERMI2D|" \
215 "VPERMI2PD|VPERMI2PS|VPERMI2Q|VPERMI2W|VPERMILPD|VPERMILPS|VPERMPD|VPERMPS|" \
216 "VPERMQ|VPERMT2B|VPERMT2D|VPERMT2PD|VPERMT2PS|VPERMT2Q|VPERMT2W|VPERMW|" \
217 "VPEXPANDD|VPEXPANDQ|VPGATHERDD|VPGATHERDQ|VPGATHERQD|VPGATHERQQ|VPLZCNTD|" \
218 "VPLZCNTQ|VPMADD52HUQ|VPMADD52LUQ|VPMASKMOV|VPMOVB2M|VPMOVD2M|VPMOVDB|" \
219 "VPMOVDW|VPMOVM2B|VPMOVM2D|VPMOVM2Q|VPMOVM2W|VPMOVQ2M|VPMOVQB|VPMOVQD|" \
220 "VPMOVQW|VPMOVSDB|VPMOVSDW|VPMOVSQB|VPMOVSQD|VPMOVSQW|VPMOVSWB|VPMOVUSDB|" \
221 "VPMOVUSDW|VPMOVUSQB|VPMOVUSQD|VPMOVUSQW|VPMOVUSWB|VPMOVW2M|VPMOVWB|" \
222 "VPMULTISHIFTQB|VPROLD|VPROLQ|VPROLVD|VPROLVQ|VPRORD|VPRORQ|VPRORVD|" \
223 "VPRORVQ|VPSCATTERDD|VPSCATTERDQ|VPSCATTERQD|VPSCATTERQQ|VPSLLVD|VPSLLVQ|" \
224 "VPSLLVW|VPSRAVD|VPSRAVQ|VPSRAVW|VPSRLVD|VPSRLVQ|VPSRLVW|VPTERNLOGD|" \
225 "VPTERNLOGQ|VPTESTMB|VPTESTMD|VPTESTMQ|VPTESTMW|VPTESTNMB|VPTESTNMD|" \
226 "VPTESTNMQ|VPTESTNMW|VRANGEPD|VRANGEPS|VRANGESD|VRANGESS|VRCP14PD|VRCP14PS|" \
227 "VRCP14SD|VRCP14SS|VREDUCEPD|VREDUCEPS|VREDUCESD|VREDUCESS|VRNDSCALEPD|" \
228 "VRNDSCALEPS|VRNDSCALESD|VRNDSCALESS|VRSQRT14PD|VRSQRT14PS|VRSQRT14SD|" \
229 "VRSQRT14SS|VSCALEFPD|VSCALEFPS|VSCALEFSD|VSCALEFSS|VSCATTERDPD|" \
230 "VSCATTERDPS|VSCATTERQPD|VSCATTERQPS|VSHUFF32x4|VSHUFF64x2|VSHUFI32x4|" \
231 "VSHUFI64x2|VTESTPD|VTESTPS|VZEROALL|VZEROUPPER|WAIT|WBINVD|WRFSBASE|" \
232 "WRGSBASE|WRMSR|WRPKRU|XABORT|XACQUIRE|XADD|XBEGIN|XCHG|XEND|XGETBV|XLAT|" \
233 "XLATB|XOR|XORPD|XORPS|XRELEASE|XRSTOR|XRSTORS|XSAVE|XSAVEC|XSAVEOPT|" \
234 "XSAVES|XSETBV|XTEST"
235
237{
238 //{ TOKEN_TYPE::WhiteSpace, R"((\s+))" },
239 { TOKEN_TYPE::WhiteSpace, R"(([ \t]+))" },
240 { TOKEN_TYPE::NewLine, R"((\n))" },
241 { TOKEN_TYPE::Comment, R"((;.*\n))" },
242 { TOKEN_TYPE::HexNumber, R"(([0-9][0-9a-f]*h))" FOLLOWED_BY(R"([\s\n\+\-\*\/,=!\]\‍(\)])") },
243 { TOKEN_TYPE::DecNumber, R"(([0-9]+))" FOLLOWED_BY(R"([\s\n\+\-\*\/,=!\]\‍(\)])") },
244 { TOKEN_TYPE::String, R"((\".*\"))" },
245
246 { TOKEN_TYPE::BraceOpen, R"((\‍())"},
247 { TOKEN_TYPE::BraceClose, R"((\)))"},
248 { TOKEN_TYPE::MemRefStart, R"((\[))"},
249 { TOKEN_TYPE::MemRefEnd, R"((\]))"},
250 { TOKEN_TYPE::Colon, R"((\:))"},
251 { TOKEN_TYPE::Operator, R"(([,\+\-\*\/\:]))"},
252 { TOKEN_TYPE::StringDef, R"((<.+>))" },
253
254 { TOKEN_TYPE::KW_include, R"((include))" FOLLOWED_BY(R"([\s])") },
255 { TOKEN_TYPE::KW_option, R"((option))" FOLLOWED_BY(R"([\s])") },
256 { TOKEN_TYPE::KW_model, R"((\.model))" FOLLOWED_BY(R"([\s])") },
257 { TOKEN_TYPE::KW_const, R"((\.const))" FOLLOWED_BY(R"([\s])") },
258 { TOKEN_TYPE::KW_code, R"((\.code))" FOLLOWED_BY(R"([\s])") },
259 { TOKEN_TYPE::KW_endprolog, R"((\.endprolog))" FOLLOWED_BY(R"([\s])") },
260 { TOKEN_TYPE::KW_ALIGN, R"((ALIGN))" FOLLOWED_BY(R"([\s])") },
261 { TOKEN_TYPE::KW_EXTERN, R"((EXTERN))" FOLLOWED_BY(R"([\s])") },
262 { TOKEN_TYPE::KW_EXTERN, R"((EXTRN))" FOLLOWED_BY(R"([\s])") },
263 { TOKEN_TYPE::KW_PUBLIC, R"((PUBLIC))" FOLLOWED_BY(R"([\s])") },
264 { TOKEN_TYPE::KW_ENDM, R"((ENDM))" FOLLOWED_BY(R"([\s\;])") },
265 { TOKEN_TYPE::KW_END, R"((END))" FOLLOWED_BY(R"([\s])") },
266 { TOKEN_TYPE::KW_if, R"((if))" FOLLOWED_BY(R"([\s])") },
267 { TOKEN_TYPE::KW_ifdef, R"((ifdef))" FOLLOWED_BY(R"([\s])")},
268 { TOKEN_TYPE::KW_ifndef, R"((ifndef))" FOLLOWED_BY(R"([\s])")},
269 { TOKEN_TYPE::KW_else, R"((else))" FOLLOWED_BY(R"([\s])")},
270 { TOKEN_TYPE::KW_endif, R"((endif))" FOLLOWED_BY(R"([\s])")},
271
272 { TOKEN_TYPE::KW_allocstack, R"((.allocstack))" FOLLOWED_BY(R"([\s])") },
273 { TOKEN_TYPE::KW_savereg, R"((.savereg))" FOLLOWED_BY(R"([\s])") },
274 { TOKEN_TYPE::KW_savexmm128, R"((.savexmm128))" FOLLOWED_BY(R"([\s])") },
275
276 { TOKEN_TYPE::KW_DB, R"((DB))" FOLLOWED_BY(R"([\s])") },
277 { TOKEN_TYPE::KW_DW, R"((DW))" FOLLOWED_BY(R"([\s])") },
278 { TOKEN_TYPE::KW_DD, R"((DD))" FOLLOWED_BY(R"([\s])") },
279 { TOKEN_TYPE::KW_DQ, R"((DQ))" FOLLOWED_BY(R"([\s])") },
280 { TOKEN_TYPE::KW_EQU, R"((EQU))" FOLLOWED_BY(R"([\s])") },
281 { TOKEN_TYPE::KW_TEXTEQU, R"((TEXTEQU))" FOLLOWED_BY(R"([\s])") },
282 { TOKEN_TYPE::KW_MACRO, R"((MACRO))" FOLLOWED_BY(R"([\s\;])") },
283 { TOKEN_TYPE::KW_PROC, R"((PROC))" FOLLOWED_BY(R"([\s\;])") },
284 { TOKEN_TYPE::KW_FRAME, R"((FRAME))" FOLLOWED_BY(R"([\s\;])") },
285 { TOKEN_TYPE::KW_ENDP, R"((ENDP))" FOLLOWED_BY(R"([\s\;])") },
286 { TOKEN_TYPE::KW_RECORD, R"((RECORD))" FOLLOWED_BY(R"([\s\;])") },
287 { TOKEN_TYPE::KW_MASK, R"((MASK))" FOLLOWED_BY(R"([\s\;])")},
288 { TOKEN_TYPE::KW_ERRDEF, R"((\.ERRDEF))" FOLLOWED_BY(R"([\s\;])")},
289
290 { TOKEN_TYPE::Filename, R"(([a-z_][a-z0-9_]*\.inc))" FOLLOWED_BY(R"([\s])") },
291 { TOKEN_TYPE::InstPrefix, "(" INST_PREFIX ")" FOLLOWED_BY(R"([\s])") },
292 { TOKEN_TYPE::Instruction, "(" INSTRUCTION ")" FOLLOWED_BY(R"([\s])") },
293 { TOKEN_TYPE::Reg8, R"((al|ah|bl|bh|cl|ch|dl|dh|sil|dil|bpl|spl|r8b|r9b|r10b|r11b|r12b|r13b|r14b|r15b))" FOLLOWED_BY(R"([\s\,])") },
294 { TOKEN_TYPE::Reg16, R"((ax|bx|cx|dx|si|di|bp|sp|r8w|r9w|r10w|r11w|r12w|r13w|r14w|r15w))" FOLLOWED_BY(R"([\s\,])") },
295 { TOKEN_TYPE::Reg32, R"((eax|ebx|ecx|edx|esi|edi|ebp|esp|r8d|r9d|r10d|r11d|r12d|r13d|r14d|r15d))" FOLLOWED_BY(R"([\s\,])") },
296 { TOKEN_TYPE::Reg64, R"((rax|rbx|rcx|rdx|rsi|rdi|rbp|rsp|r8|r9|r10|r11|r12|r13|r14|r15))" FOLLOWED_BY(R"([\s\,])") },
297 { TOKEN_TYPE::RegXmm, R"((xmm0|xmm1|xmm2|xmm3|xmm4|xmm5|xmm6|xmm7|xmm8|xmm9|xmm10|xmm11|xmm12|xmm13|xmm14|xmm15))" FOLLOWED_BY(R"([\s\,])") },
298 { TOKEN_TYPE::BYTE_PTR, R"((BYTE[\s]+PTR))" FOLLOWED_BY(R"([\s\[])") },
299 { TOKEN_TYPE::WORD_PTR, R"((WORD[\s]+PTR))" FOLLOWED_BY(R"([\s\[])") },
300 { TOKEN_TYPE::DWORD_PTR, R"((DWORD[\s]+PTR))" FOLLOWED_BY(R"([\s\[])") },
301 { TOKEN_TYPE::QWORD_PTR, R"((QWORD[\s]+PTR))" FOLLOWED_BY(R"([\s\[])") },
302 { TOKEN_TYPE::XMMWORD_PTR, R"((XMMWORD[\s]+PTR))" FOLLOWED_BY(R"([\s\[])") },
303
304 { TOKEN_TYPE::Identifier, R"((@@))" FOLLOWED_BY(SEPARATOR)},
305 { TOKEN_TYPE::Identifier, R"((@[a-z_][a-z0-9_]*))" FOLLOWED_BY(SEPARATOR)},
306 { TOKEN_TYPE::Identifier, R"(([a-z_][a-z0-9_]*))" FOLLOWED_BY(SEPARATOR)},
307
308};
309
310// FIXME: use context?
311unsigned int g_label_number = 0;
312
313bool g_processing_jmp = false;
314
316
317enum class IDTYPE
318{
319 Memory,
320 Register,
321 Label,
322 Constant,
323 Macro,
325 String,
326 Unknown
327};
328
330{
331 string Name;
333};
334
336
337static
338void
340{
341 g_identifiers.push_back(IDENTIFIER{ tok.str(), type });
342 //fprintf(stderr, "Added id: '%s'\n", tok.str().c_str());
343}
344
345void
347{
349}
350
351bool
353{
354 for (IDENTIFIER& identifier : g_identifiers)
355 {
356 if (identifier.Name == tok.str())
357 {
358 return identifier.Type == IDTYPE::Memory;
359 }
360 }
361
362 return true;
363}
364
365bool
366iequals(const string &a, const string &b)
367{
368 size_t sz = a.size();
369 if (b.size() != sz)
370 return false;
371 for (unsigned int i = 0; i < sz; ++i)
372 if (tolower(a[i]) != tolower(b[i]))
373 return false;
374 return true;
375}
376
377const char*
379{
380 const struct
381 {
382 const char* masm;
383 const char* gas;
384 } operators[] = {
385 {"and", "&"}, {"or", "|"}, {"shl", "<<"}, {"shr", ">>"}, {"not", "~"},
386 {"eq", "=="}, {"ne", "!="}, {"lt", "<"}, {"le", "<="}, {"gt", ">"}, {"ge", ">="},
387 };
388
389 for (const auto& entry : operators)
390 {
391 if (iequals(op, entry.masm))
392 return entry.gas;
393 }
394
395 return nullptr;
396}
397
398Token
400{
401 if (tok.type() != type)
402 {
403 throw "Not white space after identifier!\n";
404 }
405
406 return tok;
407}
408
410{
411 int type = tok.type();
412 if (type != TOKEN_TYPE::WhiteSpace)
413 {
414 throw "Not white space after identifier!\n";
415 }
416
417 return tok;
418}
419
421{
422 int type = tok.type();
423 if ((type != TOKEN_TYPE::WhiteSpace) &&
424 (type != TOKEN_TYPE::NewLine))
425 {
426 throw "Not white space after identifier!\n";
427 }
428
429 return tok;
430}
431
433{
434 for (string &s : list)
435 {
436 if (s == str)
437 {
438 return true;
439 }
440 }
441
442 return false;
443}
444
445size_t
446translate_token(TokenList& tokens, size_t index, const vector<string> &macro_params)
447{
448 Token tok = tokens[index];
449 switch (tok.type())
450 {
451 case TOKEN_TYPE::Comment:
452 printf("//%s", tok.str().c_str() + 1);
453 break;
454
455 case TOKEN_TYPE::DecNumber:
456 {
457 unsigned long long num = stoull(tok.str(), nullptr, 10);
458 printf("%llu", num);
459 break;
460 }
461
462 case TOKEN_TYPE::HexNumber:
463 {
464 string number = tok.str();
465 printf("0x%s", number.substr(0, number.size() - 1).c_str());
466 break;
467 }
468
469 case TOKEN_TYPE::Identifier:
470 if (is_string_in_list(macro_params, tok.str()))
471 {
472 printf("\\");
473 }
474 printf("%s", tok.str().c_str());
475 break;
476
477 // We migt want to improve these
478 case TOKEN_TYPE::BYTE_PTR:
479 case TOKEN_TYPE::WORD_PTR:
480 case TOKEN_TYPE::DWORD_PTR:
481 case TOKEN_TYPE::QWORD_PTR:
482 case TOKEN_TYPE::XMMWORD_PTR:
483
484 // Check these. valid only in instructions?
485 case TOKEN_TYPE::Reg8:
486 case TOKEN_TYPE::Reg16:
487 case TOKEN_TYPE::Reg32:
488 case TOKEN_TYPE::Reg64:
489 case TOKEN_TYPE::RegXmm:
490 case TOKEN_TYPE::Instruction:
491
492 case TOKEN_TYPE::WhiteSpace:
493 case TOKEN_TYPE::NewLine:
494 case TOKEN_TYPE::Operator:
495 printf("%s", tok.str().c_str());
496 break;
497
498 default:
499 printf("%s", tok.str().c_str());
500 break;
501 }
502
503 return index + 1;
504}
505
506size_t complete_line(TokenList &tokens, size_t index, const vector<string> &macro_params)
507{
508 while (index < tokens.size())
509 {
510 Token tok = tokens[index];
511 index = translate_token(tokens, index, macro_params);
512 if ((tok.type() == TOKEN_TYPE::NewLine) ||
513 (tok.type() == TOKEN_TYPE::Comment))
514 {
515 break;
516 }
517 }
518
519 return index;
520}
521
522size_t
523translate_expression(TokenList &tokens, size_t index, const vector<string> &macro_params)
524{
525 while (index < tokens.size())
526 {
527 Token tok = tokens[index];
528 switch (tok.type())
529 {
530 case TOKEN_TYPE::NewLine:
531 case TOKEN_TYPE::Comment:
532 return index;
533
534 case TOKEN_TYPE::KW_MASK:
535 printf("MASK_");
536 index += 2;
537 break;
538
539 case TOKEN_TYPE::Instruction:
540 {
541 const char* op = get_expression_operator(tok.str());
542 if (!op)
543 {
544 throw "Invalid expression";
545 }
546 printf("%s", op);
547 index += 1;
548 break;
549 }
550
551 case TOKEN_TYPE::Operator:
552 if (tok.str() == ",")
553 {
554 return index;
555 }
556 index = translate_token(tokens, index, macro_params);
557 break;
558
559 case TOKEN_TYPE::Identifier:
560 {
561 const char* op = get_expression_operator(tok.str());
562 if (op)
563 {
564 printf("%s", op);
565 index += 1;
566 }
567 else
568 {
569 index = translate_token(tokens, index, macro_params);
570 }
571 break;
572 }
573
574 case TOKEN_TYPE::WhiteSpace:
575 case TOKEN_TYPE::BraceOpen:
576 case TOKEN_TYPE::BraceClose:
577 case TOKEN_TYPE::DecNumber:
578 case TOKEN_TYPE::HexNumber:
579 index = translate_token(tokens, index, macro_params);
580 break;
581
582 default:
583 index = translate_token(tokens, index, macro_params);
584 }
585 }
586
587 return index;
588}
589
590size_t translate_mem_ref(TokenList& tokens, size_t index, const vector<string>& macro_params)
591{
592 unsigned int offset = 0;
593
594 Token tok = tokens[index];
595
596 if ((tok.type() == TOKEN_TYPE::DecNumber) ||
597 (tok.type() == TOKEN_TYPE::HexNumber))
598 {
599 offset = stoi(tok.str(), nullptr, 0);
600 index += 2;
601 }
602
603 index = translate_token(tokens, index, macro_params);
604
605 while (index < tokens.size())
606 {
607 Token tok = tokens[index];
608 index = translate_token(tokens, index, macro_params);
609 if (tok.type() == TOKEN_TYPE::MemRefEnd)
610 {
611 if (offset != 0)
612 {
613 printf(" + %u", offset);
614 }
615 return index;
616 }
617 }
618
619 throw "Failed to translate memory ref";
620 return index;
621}
622
623static
624bool
626{
627 return ((tok.type() == TOKEN_TYPE::DecNumber) ||
628 (tok.type() == TOKEN_TYPE::HexNumber));
629}
630
631static
632size_t
634{
635 if ((index < tokens.size()) &&
636 (tokens[index].type() == TOKEN_TYPE::WhiteSpace))
637 {
638 index++;
639 }
640
641 return index;
642}
643
644static
645size_t
646translate_rip_relative_offset(TokenList& tokens, size_t index, const vector<string>& macro_params)
647{
648 size_t operatorIndex = skip_whitespace(tokens, index);
649 if ((operatorIndex == tokens.size()) ||
650 (tokens[operatorIndex].type() != TOKEN_TYPE::Operator) ||
651 ((tokens[operatorIndex].str() != "+") &&
652 (tokens[operatorIndex].str() != "-")))
653 {
654 return index;
655 }
656
657 size_t numberIndex = skip_whitespace(tokens, operatorIndex + 1);
658 if ((numberIndex == tokens.size()) ||
659 !is_number_token(tokens[numberIndex]))
660 {
661 return index;
662 }
663
664 while (index <= numberIndex)
665 {
666 index = translate_token(tokens, index, macro_params);
667 }
668
669 return index;
670}
671
672size_t translate_instruction_param(TokenList& tokens, size_t index, const vector<string>& macro_params)
673{
674 switch (tokens[index].type())
675 {
676 case TOKEN_TYPE::BYTE_PTR:
677 case TOKEN_TYPE::WORD_PTR:
678 case TOKEN_TYPE::DWORD_PTR:
679 case TOKEN_TYPE::QWORD_PTR:
680 case TOKEN_TYPE::XMMWORD_PTR:
681 index = translate_token(tokens, index, macro_params);
682
683 // Optional whitespace
684 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
685 {
686 index = translate_token(tokens, index, macro_params);
687 }
688 }
689
690 while (index < tokens.size())
691 {
692 Token tok = tokens[index];
693 switch (tok.type())
694 {
695 case TOKEN_TYPE::MemRefStart:
696 return translate_mem_ref(tokens, index, macro_params);
697
698 case TOKEN_TYPE::NewLine:
699 case TOKEN_TYPE::Comment:
700 return index;
701
702 case TOKEN_TYPE::Operator:
703 if (tok.str() == ",")
704 return index;
705 return translate_token(tokens, index, macro_params);
706
707 case TOKEN_TYPE::Identifier:
708 index = translate_token(tokens, index, macro_params);
709 if (is_mem_id(tok) &&
710 !is_string_in_list(macro_params, tok.str()) &&
712 {
713 index = translate_rip_relative_offset(tokens, index, macro_params);
714 printf("[rip]");
715 }
716 break;
717
718 default:
719 index = translate_expression(tokens, index, macro_params);
720 }
721 }
722
723 return index;
724}
725
726static
727bool
729{
730 const char* inst_list[] = {
731 "jmp", "call", "ja", "jae", "jb", "jbe", "jc", "jcxz", "je", "jecxz", "jg", "jge",
732 "jl", "jle", "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle",
733 "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "jrcxz", "js", "jz", "loop", "loope",
734 "loopne", "loopnz", "loopz"
735 };
736
737 for (const char* inst : inst_list)
738 {
739 if (iequals(tok.str(), inst))
740 {
741 return true;
742 }
743 }
744
745 return false;
746}
747
748size_t translate_instruction(TokenList& tokens, size_t index, const vector<string>& macro_params)
749{
750 // Check for jump/call instructions
751 if (is_jmp_or_call(tokens[index]))
752 {
753 g_processing_jmp = true;
754 }
755
756 // Translate the instruction itself
757 index = translate_token(tokens, index, macro_params);
758
759 // Handle instruction parameters
760 while (index < tokens.size())
761 {
762 // Optional whitespace
763 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
764 {
765 index = translate_token(tokens, index, macro_params);
766 }
767
768 // Check for parameters
769 Token tok = tokens[index];
770 switch (tok.type())
771 {
772 case TOKEN_TYPE::Comment:
773 case TOKEN_TYPE::NewLine:
774 g_processing_jmp = false;
775 return index;
776
777 case TOKEN_TYPE::WhiteSpace:
778 case TOKEN_TYPE::Operator:
779 index = translate_token(tokens, index, macro_params);
780 break;
781
782 default:
783 index = translate_instruction_param(tokens, index, macro_params);
784 break;
785 }
786 }
787
788 g_processing_jmp = false;
789 return index;
790}
791
792size_t translate_item(TokenList& tokens, size_t index, const vector<string> &macro_params)
793{
794 switch (tokens[index].type())
795 {
796 case TOKEN_TYPE::DecNumber:
797 case TOKEN_TYPE::HexNumber:
798 case TOKEN_TYPE::String:
799 case TOKEN_TYPE::WhiteSpace:
800 return translate_token(tokens, index, macro_params);
801 }
802
803 throw "Failed to translate item";
804 return -1;
805}
806
807size_t translate_list(TokenList& tokens, size_t index, const vector<string> &macro_params)
808{
809 while (index < tokens.size())
810 {
811 // The item itself
812 index = translate_item(tokens, index, macro_params);
813
814 // Optional white space
815 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
816 {
817 index = translate_token(tokens, index, macro_params);
818 }
819
820 // End of list?
821 if ((tokens[index].type() == TOKEN_TYPE::Comment) ||
822 (tokens[index].type() == TOKEN_TYPE::NewLine))
823 {
824 return index;
825 }
826
827 // We expect a comma here
828 if ((tokens[index].type() != TOKEN_TYPE::Operator) ||
829 (tokens[index].str() != ","))
830 {
831 throw "Unexpected end of list";
832 }
833
834 index = translate_token(tokens, index, macro_params);
835 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
836 {
837 index = translate_token(tokens, index, macro_params);
838 }
839 }
840
841 throw "Failed to translate list";
842 return -1;
843}
844
845size_t
846translate_data_def(TokenList& tokens, size_t index, const vector<string>& macro_params)
847{
848 Token tok = tokens[index];
849 Token tok1 = get_ws(tokens[index + 1]);
850 string directive, need, have ="";
851
852 switch (tok.type())
853 {
854 case TOKEN_TYPE::KW_DB:
855 directive = ".byte";
856 break;
857
858 case TOKEN_TYPE::KW_DW:
859 directive = ".short";
860 break;
861
862 case TOKEN_TYPE::KW_DD:
863 directive = ".long";
864 break;
865
866 case TOKEN_TYPE::KW_DQ:
867 directive = ".quad";
868 break;
869 }
870
871 index += 2;
872
873 while (index < tokens.size())
874 {
875 // Check if we need '.ascii' for ASCII strings
876 if (tokens[index].str()[0] == '\"')
877 {
878 need = ".ascii";
879 }
880 else
881 {
882 need = directive;
883 }
884
885 // Output the directive we need (or a comma)
886 if (have == "")
887 {
888 printf("%s ", need.c_str());
889 }
890 else if (have != need)
891 {
892 printf("\n%s ", need.c_str());
893 }
894 else
895 {
896 printf(", ");
897 }
898
899 have = need;
900
901 // Check if this is an identifier
902 if (tokens[index].type() == TOKEN_TYPE::Identifier)
903 {
904 // Assume this is a memory reference or a constant
905 index = translate_token(tokens, index, macro_params);
906 }
907 else
908 {
909 // The item itself
910 index = translate_item(tokens, index, macro_params);
911 }
912
913 // Optional white space
914 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
915 {
916 index = translate_token(tokens, index, macro_params);
917 }
918
919 // End of list?
920 if ((tokens[index].type() == TOKEN_TYPE::Comment) ||
921 (tokens[index].type() == TOKEN_TYPE::NewLine))
922 {
923 return index;
924 }
925
926 // We expect a comma here
927 if ((tokens[index].type() != TOKEN_TYPE::Operator) ||
928 (tokens[index].str() != ","))
929 {
930 throw "Unexpected end of list";
931 }
932
933 // Skip comma and optional white-space
934 index++;
935 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
936 {
937 index++;
938 }
939
940 // Check if the list continues after a line break
941 if ((tokens[index].type() == TOKEN_TYPE::NewLine) ||
942 (tokens[index].type() == TOKEN_TYPE::Comment))
943 {
944 index++;
945 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
946 {
947 index++;
948 }
949 }
950
951 }
952
953 throw "Failed to translate list";
954 return -1;
955}
956
957size_t
958translate_construct_one_param(string translated, TokenList& tokens, size_t index, const vector<string>& macro_params)
959{
960 // The next token should be white space
961 Token tok1 = get_ws(tokens[index + 1]);
962
963 printf("%s%s", translated.c_str(), tok1.str().c_str());
964 return translate_expression(tokens, index + 2, macro_params);
965}
966
967size_t
968translate_record(TokenList &tokens, size_t index, const vector<string> &macro_params)
969{
970 unsigned int bits, bitpos = 0;
971 unsigned long long oldmask = 0, mask = 0;
972
973 Token tok_name = get_expected_token(tokens[index], TOKEN_TYPE::Identifier);
974 index += 4;
975 while (index < tokens.size())
976 {
977 Token tok_member = get_expected_token(tokens[index++], TOKEN_TYPE::Identifier);
978
979 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
980 {
981 index++;
982 }
983
984 if (tokens[index++].str() != ":")
985 {
986 throw "Unexpected token";
987 }
988
989 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
990 {
991 index++;
992 }
993
994 Token tok_bits = tokens[index++];
995 if ((tok_bits.type() != TOKEN_TYPE::DecNumber) &&
996 (tok_bits.type() != TOKEN_TYPE::HexNumber))
997 {
998 throw "Unexpected token";
999 }
1000
1001 bits = stoi(tok_bits.str(), nullptr, 0);
1002
1003 printf("%s = %u\n", tok_member.str().c_str(), bitpos);
1004
1005 oldmask = (1ULL << bitpos) - 1;
1006 bitpos += bits;
1007 mask = (1ULL << bitpos) - 1 - oldmask;
1008 printf("MASK_%s = 0x%llx\n", tok_member.str().c_str(), mask);
1009
1010 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
1011 {
1012 index++;
1013 }
1014
1015 if ((tokens[index].type() == TOKEN_TYPE::NewLine) ||
1016 (tokens[index].type() == TOKEN_TYPE::Comment))
1017 {
1018 break;
1019 }
1020
1021 if (tokens[index].str() != ",")
1022 {
1023 throw "unexpected token";
1024 }
1025
1026 index++;
1027 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
1028 {
1029 index++;
1030 }
1031
1032 if ((tokens[index].type() == TOKEN_TYPE::NewLine) ||
1033 (tokens[index].type() == TOKEN_TYPE::Comment))
1034 {
1035 index++;
1036 }
1037
1038 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
1039 {
1040 index++;
1041 }
1042 }
1043
1044 return index;
1045}
1046
1047static
1048bool
1049find_proc_frame(TokenList& tokens, size_t index, size_t& frameEndIndex)
1050{
1051 while (index < tokens.size())
1052 {
1053 Token tok = tokens[index];
1054 if ((tok.type() == TOKEN_TYPE::NewLine) ||
1055 (tok.type() == TOKEN_TYPE::Comment))
1056 {
1057 return false;
1058 }
1059
1060 if (tok.type() == TOKEN_TYPE::KW_FRAME)
1061 {
1062 frameEndIndex = index + 1;
1063 return true;
1064 }
1065
1066 index++;
1067 }
1068
1069 return false;
1070}
1071
1072size_t
1074{
1075 Token tok = tokens[index];
1076 Token tok1 = tokens[index + 1];
1077
1078 if (tok1.type() == TOKEN_TYPE::Colon)
1079 {
1080 if (tok.str() == "@@")
1081 {
1083 printf("%u:", g_label_number);
1084 }
1085 else
1086 {
1087 printf("%s:", tok.str().c_str());
1088 }
1090 return index + 2;
1091 }
1092
1093 Token tok2 = tokens[index + 2];
1094
1095 switch (tok2.type())
1096 {
1097 case TOKEN_TYPE::KW_MACRO:
1098 throw "Cannot have a nested macro!";
1099
1100 case TOKEN_TYPE::KW_DB:
1101 case TOKEN_TYPE::KW_DW:
1102 case TOKEN_TYPE::KW_DD:
1103 case TOKEN_TYPE::KW_DQ:
1104 printf("%s:%s", tok.str().c_str(), tok1.str().c_str());
1105 add_mem_id(tok);
1106 return translate_data_def(tokens, index + 2, macro_params);
1107
1108 case TOKEN_TYPE::KW_EQU:
1109 //printf("%s%s", tok.str().c_str(), tok1.str().c_str());
1110 printf("#define %s ", tok.str().c_str());
1112 return translate_expression(tokens, index + 3, macro_params);
1113
1114 case TOKEN_TYPE::KW_TEXTEQU:
1115 {
1116 Token tok3 = get_ws(tokens[index + 3]);
1117 Token tok4 = get_expected_token(tokens[index + 4], TOKEN_TYPE::StringDef);
1118
1119 string textdef = tok4.str();
1120 printf("#define %s %s", tok.str().c_str(), textdef.substr(1, textdef.size() - 2).c_str());
1122 return index + 5;
1123 }
1124
1125 case TOKEN_TYPE::KW_PROC:
1126 {
1127 printf("%s:", tok.str().c_str());
1128 index += 3;
1129
1130 size_t frameEndIndex;
1131 bool hasFrame = find_proc_frame(tokens, index, frameEndIndex);
1132 g_proc_frame_stack.push_back(hasFrame);
1133
1134 if (hasFrame)
1135 {
1136#ifdef TARGET_amd64
1137 printf("\n.seh_proc %s\n", tok.str().c_str());
1138#else
1139 printf("\n.cfi_startproc\n");
1140#endif
1141 index = frameEndIndex;
1142 }
1144 break;
1145 }
1146
1147 case TOKEN_TYPE::KW_ENDP:
1148 {
1149 bool hasFrame = false;
1150 if (!g_proc_frame_stack.empty())
1151 {
1152 hasFrame = g_proc_frame_stack.back();
1153 g_proc_frame_stack.pop_back();
1154 }
1155
1156 if (hasFrame)
1157 {
1158#ifdef TARGET_amd64
1159 printf(".seh_endproc");
1160#else
1161 printf(".cfi_endproc");
1162#endif
1163 }
1164 index += 3;
1165 break;
1166 }
1167
1168 case TOKEN_TYPE::KW_RECORD:
1169 index = translate_record(tokens, index, macro_params);
1170 break;
1171
1172 default:
1173 // We don't know what it is, assume it's a macro and treat it like an instruction
1174 index = translate_instruction(tokens, index, macro_params);
1175 break;
1176 }
1177
1178 return index;
1179}
1180
1181static bool g_intel_syntax_emitted = false;
1182
1183size_t
1184translate_construct(TokenList& tokens, size_t index, const vector<string> &macro_params)
1185{
1186 Token tok = tokens[index];
1187
1188 switch (tok.type())
1189 {
1190 case TOKEN_TYPE::WhiteSpace:
1191 case TOKEN_TYPE::NewLine:
1192 case TOKEN_TYPE::Comment:
1193 return translate_token(tokens, index, macro_params);
1194
1195 case TOKEN_TYPE::Identifier:
1196 return translate_identifier_construct(tokens, index, macro_params);
1197
1198 case TOKEN_TYPE::KW_ALIGN:
1199 index = translate_construct_one_param(".align", tokens, index, macro_params);
1200 break;
1201
1202 case TOKEN_TYPE::KW_allocstack:
1203 index = translate_construct_one_param(".seh_stackalloc", tokens, index, macro_params);
1204 break;
1205
1206 case TOKEN_TYPE::KW_code:
1207 {
1208 printf(".text\n");
1209#ifdef TARGET_amd64
1210 printf(".code64\n");
1211#else
1212 printf(".code32\n");
1213#endif
1215 {
1216 printf(".intel_syntax noprefix\n");
1218 }
1219 index++;
1220 break;
1221 }
1222
1223 case TOKEN_TYPE::KW_const:
1224 printf(".section .rdata");
1225 index++;
1226 break;
1227
1228 case TOKEN_TYPE::KW_DB:
1229 case TOKEN_TYPE::KW_DW:
1230 case TOKEN_TYPE::KW_DD:
1231 case TOKEN_TYPE::KW_DQ:
1232 return translate_data_def(tokens, index, macro_params);
1233
1234 case TOKEN_TYPE::KW_END:
1235 printf("// END\n");
1236 return tokens.size();
1237
1238 case TOKEN_TYPE::KW_endprolog:
1239 printf(".seh_endprologue");
1240 index++;
1241 break;
1242
1243 case TOKEN_TYPE::KW_EXTERN:
1244 {
1245 Token tok1 = get_ws_or_nl(tokens[index + 1]);
1246 Token tok2 = get_expected_token(tokens[index + 2], TOKEN_TYPE::Identifier);
1247 add_mem_id(tok2);
1248 printf("//");
1249 return complete_line(tokens, index, macro_params);
1250 }
1251
1252 case TOKEN_TYPE::KW_if:
1253 printf(".");
1254 return translate_expression(tokens, index, macro_params);
1255
1256 case TOKEN_TYPE::KW_ifdef:
1257 case TOKEN_TYPE::KW_ifndef:
1258 case TOKEN_TYPE::KW_else:
1259 case TOKEN_TYPE::KW_endif:
1260 printf(".");
1261 return complete_line(tokens, index, macro_params);
1262
1263 case TOKEN_TYPE::KW_include:
1264 {
1265 // The next token should be white space
1266 Token tok1 = get_ws_or_nl(tokens[index + 1]);
1267 Token tok2 = get_expected_token(tokens[index + 2], TOKEN_TYPE::Filename);
1268 printf("#include \"%s.h\"", tok2.str().c_str());
1269 index += 3;
1270 break;
1271 }
1272
1273 case TOKEN_TYPE::KW_option:
1274 {
1275 // The next token should be white space, followed by an identifier
1276 Token tok1 = get_ws(tokens[index + 1]);
1277 Token tok2 = get_expected_token(tokens[index + 2], TOKEN_TYPE::Identifier);
1278
1279 // We just ignore this for now and just print it as a comment
1280 printf("//");
1281 return complete_line(tokens, index, macro_params);
1282 }
1283
1284 case TOKEN_TYPE::KW_model:
1285 {
1286 // The next token should be white space, followed by an identifier
1287 Token tok1 = get_ws(tokens[index + 1]);
1288 Token tok2 = get_expected_token(tokens[index + 2], TOKEN_TYPE::Identifier);
1289
1290 // Check if the model is valid (we only support flat)
1291 if (_stricmp(tok2.str().c_str(), "FLAT") != 0)
1292 {
1293 throw "Invalid model";
1294 }
1295
1296 index += 3;
1297
1298 // Skip optional white space
1299 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
1300 {
1301 index++;
1302 }
1303
1304 // Check if it is followed by a comma and another identifier
1305 if (tokens[index].type() == TOKEN_TYPE::Operator &&
1306 tokens[index].str() == ",")
1307 {
1308 // This could be "C" or "STDCALL", but we don't handle those yet
1309 throw "Invalid model";
1310 }
1311
1312 return complete_line(tokens, index, macro_params);
1313 }
1314
1315 case TOKEN_TYPE::KW_PUBLIC:
1316 index = translate_construct_one_param(".global", tokens, index, macro_params);
1317 break;
1318
1319 case TOKEN_TYPE::KW_savereg:
1320 printf(".seh_savereg");
1321 return complete_line(tokens, index + 1, macro_params);
1322
1323 case TOKEN_TYPE::KW_savexmm128:
1324 printf(".seh_savexmm");
1325 return complete_line(tokens, index + 1, macro_params);
1326
1327 case TOKEN_TYPE::InstPrefix:
1328 {
1329 // The next token should be white space, followed by an instruction
1330 Token tok1 = get_ws(tokens[index + 1]);
1331 Token tok2 = get_expected_token(tokens[index + 2], TOKEN_TYPE::Instruction);
1332 printf("%s%s", tok.str().c_str(), tok1.str().c_str());
1333 index += 2;
1334 /* Fall through */
1335 }
1336 case TOKEN_TYPE::Instruction:
1337 index = translate_instruction(tokens, index, macro_params);
1338 break;
1339
1340 case TOKEN_TYPE::KW_ERRDEF:
1341 printf("//");
1342 return complete_line(tokens, index, macro_params);
1343
1344 default:
1345 throw "failed to translate construct";
1346 }
1347
1348 // Skip optional white-space
1349 if (tokens[index].type() == TOKEN_TYPE::WhiteSpace)
1350 {
1351 index++;
1352 }
1353
1354 // Line should end here!
1355 Token end = tokens[index];
1356 if ((end.type() != TOKEN_TYPE::Comment) &&
1357 (end.type() != TOKEN_TYPE::NewLine))
1358 {
1359 throw "unexpected tokens";
1360 }
1361
1362 return index;
1363}
1364
1365size_t
1367{
1368 vector<string> macro_params;
1369
1370 printf(".macro %s", tokens[index].str().c_str());
1371
1372 // Parse marameters
1373 index += 3;
1374 while (index < tokens.size())
1375 {
1376 Token tok = tokens[index];
1377 switch (tok.type())
1378 {
1379 case TOKEN_TYPE::NewLine:
1380 case TOKEN_TYPE::Comment:
1381 index = translate_token(tokens, index, macro_params);
1382 break;
1383
1384 case TOKEN_TYPE::Identifier:
1385 macro_params.push_back(tok.str());
1386 printf("%s", tok.str().c_str());
1387 index++;
1388 continue;
1389
1390 case TOKEN_TYPE::WhiteSpace:
1391 case TOKEN_TYPE::Operator:
1392 index = translate_token(tokens, index, macro_params);
1393 continue;
1394 }
1395
1396 break;
1397 }
1398
1399 // Parse content
1400 while (index < tokens.size())
1401 {
1402 Token tok = tokens[index];
1403 switch (tok.type())
1404 {
1405 case TOKEN_TYPE::KW_ENDM:
1406 printf(".endm");
1407 return index + 1;
1408
1409 default:
1410 index = translate_construct(tokens, index, macro_params);
1411 }
1412 }
1413
1414 throw "Failed to translate macro";
1415 return -1;
1416}
1417
1418void
1420{
1421 size_t index = 0;
1422 size_t size = tokens.size();
1423 vector<string> empty_macro_params;
1424
1425 while (index < size)
1426 {
1427 // Macros are special
1428 if ((tokens[index].type() == TOKEN_TYPE::Identifier) &&
1429 (tokens[index + 1].type() == TOKEN_TYPE::WhiteSpace) &&
1430 (tokens[index + 2].type() == TOKEN_TYPE::KW_MACRO))
1431 {
1432 index = translate_macro(tokens, index);
1433 }
1434 else
1435 {
1436 index = translate_construct(tokens, index, empty_macro_params);
1437 }
1438 }
1439}
1440
1441int main(int argc, char* argv[])
1442{
1443 if (argc < 2)
1444 {
1445 fprintf(stderr, "Invalid parameter!\n");
1446 return -1;
1447 }
1448
1449#if PROFILING_ENABLED
1450 time_t start_time = time(NULL);
1451#endif
1452
1453 try
1454 {
1455 // Open and read the input file
1456 string filename(argv[1]);
1459 buffer << file.rdbuf();
1460 string text = buffer.str();
1461
1462 // Create the tokenizer
1463 Tokenizer tokenizer(g_TokenList);
1464
1465 // Get a token list
1466 TokenList toklist(tokenizer, text);
1467
1468 // Now translate the tokens
1469 translate(toklist);
1470 }
1471 catch (const char* message)
1472 {
1473 fprintf(stderr, "Exception caught: '%s'\n", message);
1474 return -2;
1475 }
1476
1477#if PROFILING_ENABLED
1478 time_t total_time = time(NULL) + 1 - start_time;
1479 fprintf(stderr, "total_time = %llu\n", total_time);
1480 fprintf(stderr, "search_time = %llu\n", search_time);
1481 fprintf(stderr, "search: %llu %%\n", search_time * 100 / total_time);
1482#endif
1483
1484 return 0;
1485}
void add_mem_id(Token &tok)
Definition: asmpp.cpp:346
size_t translate_list(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:807
size_t translate_data_def(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:846
size_t translate_construct(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:1184
static void add_identifier(Token &tok, IDTYPE type)
Definition: asmpp.cpp:339
#define INST_PREFIX
Definition: asmpp.cpp:123
size_t translate_item(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:792
vector< TOKEN_DEF > g_TokenList
Definition: asmpp.cpp:236
void translate(TokenList &tokens)
Definition: asmpp.cpp:1419
size_t translate_token(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:446
Token get_ws_or_nl(Token &&tok)
Definition: asmpp.cpp:420
#define _stricmp
Definition: asmpp.cpp:24
static bool find_proc_frame(TokenList &tokens, size_t index, size_t &frameEndIndex)
Definition: asmpp.cpp:1049
static bool is_number_token(const Token &tok)
Definition: asmpp.cpp:625
#define INSTRUCTION
Definition: asmpp.cpp:126
static size_t translate_rip_relative_offset(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:646
static bool is_jmp_or_call(const Token &tok)
Definition: asmpp.cpp:728
bool is_mem_id(Token &tok)
Definition: asmpp.cpp:352
vector< bool > g_proc_frame_stack
Definition: asmpp.cpp:315
int fake_printf(const char *format,...)
Definition: asmpp.cpp:106
size_t complete_line(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:506
unsigned int g_label_number
Definition: asmpp.cpp:311
bool is_string_in_list(vector< string > list, string str)
Definition: asmpp.cpp:432
static bool g_intel_syntax_emitted
Definition: asmpp.cpp:1181
time_t search_time
Definition: asmpp.cpp:31
size_t translate_expression(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:523
#define FOLLOWED_BY(x)
Definition: asmpp.cpp:115
Token get_expected_token(Token &&tok, TOKEN_TYPE type)
Definition: asmpp.cpp:399
vector< IDENTIFIER > g_identifiers
Definition: asmpp.cpp:335
bool iequals(const string &a, const string &b)
Definition: asmpp.cpp:366
TOKEN_TYPE
Definition: asmpp.cpp:34
@ KW_allocstack
Definition: asmpp.cpp:69
@ Reg32
Definition: asmpp.cpp:93
@ KW_FRAME
Definition: asmpp.cpp:81
@ KW_savereg
Definition: asmpp.cpp:70
@ KW_EXTERN
Definition: asmpp.cpp:59
@ KW_PROC
Definition: asmpp.cpp:80
@ KW_model
Definition: asmpp.cpp:54
@ StringDef
Definition: asmpp.cpp:50
@ MemRefEnd
Definition: asmpp.cpp:47
@ KW_ENDM
Definition: asmpp.cpp:61
@ BraceClose
Definition: asmpp.cpp:45
@ Comment
Definition: asmpp.cpp:39
@ KW_else
Definition: asmpp.cpp:66
@ Instruction
Definition: asmpp.cpp:90
@ KW_END
Definition: asmpp.cpp:62
@ KW_code
Definition: asmpp.cpp:56
@ KW_endprolog
Definition: asmpp.cpp:57
@ DecNumber
Definition: asmpp.cpp:40
@ Identifier
Definition: asmpp.cpp:103
@ KW_DW
Definition: asmpp.cpp:74
@ BraceOpen
Definition: asmpp.cpp:44
@ KW_RECORD
Definition: asmpp.cpp:83
@ Colon
Definition: asmpp.cpp:48
@ KW_ENDP
Definition: asmpp.cpp:82
@ Filename
Definition: asmpp.cpp:88
@ KW_EQU
Definition: asmpp.cpp:77
@ BYTE_PTR
Definition: asmpp.cpp:96
@ RegXmm
Definition: asmpp.cpp:95
@ WhiteSpace
Definition: asmpp.cpp:37
@ KW_DB
Definition: asmpp.cpp:73
@ MemRefStart
Definition: asmpp.cpp:46
@ QWORD_PTR
Definition: asmpp.cpp:99
@ KW_include
Definition: asmpp.cpp:52
@ KW_MACRO
Definition: asmpp.cpp:79
@ HexNumber
Definition: asmpp.cpp:41
@ KW_DD
Definition: asmpp.cpp:75
@ LabelName
Definition: asmpp.cpp:102
@ KW_const
Definition: asmpp.cpp:55
@ KW_TEXTEQU
Definition: asmpp.cpp:78
@ Reg8
Definition: asmpp.cpp:91
@ NewLine
Definition: asmpp.cpp:38
@ KW_ifndef
Definition: asmpp.cpp:65
@ KW_ifdef
Definition: asmpp.cpp:64
@ XMMWORD_PTR
Definition: asmpp.cpp:100
@ KW_PUBLIC
Definition: asmpp.cpp:60
@ Operator
Definition: asmpp.cpp:49
@ KW_DQ
Definition: asmpp.cpp:76
@ Eof
Definition: asmpp.cpp:36
@ KW_ALIGN
Definition: asmpp.cpp:58
@ KW_savexmm128
Definition: asmpp.cpp:71
@ DWORD_PTR
Definition: asmpp.cpp:98
@ String
Definition: asmpp.cpp:42
@ KW_endif
Definition: asmpp.cpp:67
@ KW_MASK
Definition: asmpp.cpp:85
@ KW_if
Definition: asmpp.cpp:63
@ WORD_PTR
Definition: asmpp.cpp:97
@ InstPrefix
Definition: asmpp.cpp:89
@ Invalid
Definition: asmpp.cpp:35
@ KW_option
Definition: asmpp.cpp:53
@ Reg16
Definition: asmpp.cpp:92
@ Reg64
Definition: asmpp.cpp:94
@ KW_ERRDEF
Definition: asmpp.cpp:86
Token get_ws(Token &&tok)
Definition: asmpp.cpp:409
const char * get_expression_operator(const string &op)
Definition: asmpp.cpp:378
IDTYPE
Definition: asmpp.cpp:318
size_t translate_identifier_construct(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:1073
size_t translate_construct_one_param(string translated, TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:958
size_t translate_record(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:968
size_t translate_macro(TokenList &tokens, size_t index)
Definition: asmpp.cpp:1366
size_t translate_instruction(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:748
bool g_processing_jmp
Definition: asmpp.cpp:313
size_t translate_mem_ref(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:590
size_t translate_instruction_param(TokenList &tokens, size_t index, const vector< string > &macro_params)
Definition: asmpp.cpp:672
#define SEPARATOR
Definition: asmpp.cpp:121
#define index(s, c)
Definition: various.h:29
size_t size() const
Definition: tokenizer.hpp:239
int type() const
Definition: tokenizer.hpp:55
std::string str() const
Definition: tokenizer.hpp:50
_Self substr(size_type __pos=0, size_type __n=npos) const
Definition: _string.h:1022
const _CharT * c_str() const
Definition: _string.h:949
size_type size() const
Definition: _string.h:400
Definition: list.h:39
#define NULL
Definition: types.h:112
UINT op
Definition: effect.c:235
MonoAssembly int argc
Definition: metahost.c:107
const WCHAR * text
Definition: package.c:1826
int CDECL tolower(int c)
Definition: ctype.c:572
int WINAPIV fprintf(FILE *file, const char *format,...)
Definition: file.c:5549
__time32_t time_t
Definition: corecrt.h:228
#define stderr
int main()
Definition: test.c:6
#define printf
Definition: freeldr.h:103
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLuint index
Definition: glext.h:6031
GLenum GLint GLuint mask
Definition: glext.h:6028
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * bits
Definition: glext.h:10929
GLuint GLuint num
Definition: glext.h:9618
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define bits
Definition: infblock.c:15
const char * filename
Definition: ioapi.h:137
uint32_t entry
Definition: isohybrid.c:63
__u16 time
Definition: mkdosfs.c:8
static unsigned int number
Definition: dsound.c:1479
static UINT PSTR DWORD UINT * need
Definition: parser.c:36
#define argv
Definition: mplay32.c:18
Definition: features.h:417
static void skip_whitespace()
Definition: regtests2xml.c:188
const WCHAR * str
IDTYPE Type
Definition: asmpp.cpp:332
string Name
Definition: asmpp.cpp:331
Definition: fci.c:123
Definition: tftpd.h:60
void push_back(const _Tp &__x=_STLP_DEFAULT_CONSTRUCTED(_Tp))
Definition: _vector.h:379