mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-30 08:00:51 +00:00
ad0eee5dfe
and the rest from newtree
1079 lines
19 KiB
C
1079 lines
19 KiB
C
/*
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
//
|
|
// gas to MASM source code converter
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define MAX_TOKENS 100
|
|
#define MAX_TOKEN_LENGTH 1024
|
|
#define LF 0x0A
|
|
|
|
typedef enum {NOT_WHITESPACE, WHITESPACE, TOKEN_AVAILABLE, LINE_DONE, FILE_DONE, PARSED_OKAY} tokenstat;
|
|
typedef enum {NOSEG, DATASEG, TEXTSEG} segtype;
|
|
|
|
int tokennum;
|
|
int linein, lineout;
|
|
|
|
char *token;
|
|
char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH+1];
|
|
|
|
segtype currentseg = NOSEG;
|
|
|
|
typedef struct {
|
|
char *text;
|
|
char *emit;
|
|
int numtokens;
|
|
void (*parsefunc) (void);
|
|
} parsefield;
|
|
|
|
|
|
void errorexit (void);
|
|
|
|
|
|
//==============================================
|
|
|
|
typedef struct {
|
|
char *text;
|
|
char *emit;
|
|
int len;
|
|
} regdesc;
|
|
|
|
regdesc reglist[] = {
|
|
{"%eax", "eax", 4},
|
|
{"%ebx", "ebx", 4},
|
|
{"%ecx", "ecx", 4},
|
|
{"%edx", "edx", 4},
|
|
{"%esi", "esi", 4},
|
|
{"%edi", "edi", 4},
|
|
{"%ebp", "ebp", 4},
|
|
{"%esp", "esp", 4},
|
|
{"%ax", "ax", 3},
|
|
{"%bx", "bx", 3},
|
|
{"%cx", "cx", 3},
|
|
{"%dx", "dx", 3},
|
|
{"%si", "si", 3},
|
|
{"%di", "di", 3},
|
|
{"%bp", "bp", 3},
|
|
{"%sp", "sp", 3},
|
|
{"%al", "al", 3},
|
|
{"%bl", "bl", 3},
|
|
{"%cl", "cl", 3},
|
|
{"%dl", "dl", 3},
|
|
{"%ah", "ah", 3},
|
|
{"%bh", "bh", 3},
|
|
{"%ch", "ch", 3},
|
|
{"%dh", "dh", 3},
|
|
{"%st(0)", "st(0)", 6},
|
|
{"%st(1)", "st(1)", 6},
|
|
{"%st(2)", "st(2)", 6},
|
|
{"%st(3)", "st(3)", 6},
|
|
{"%st(4)", "st(4)", 6},
|
|
{"%st(5)", "st(5)", 6},
|
|
{"%st(6)", "st(6)", 6},
|
|
{"%st(7)", "st(7)", 6},
|
|
};
|
|
|
|
int numregs = sizeof (reglist) / sizeof (reglist[0]);
|
|
|
|
//==============================================
|
|
|
|
|
|
void emitanoperand (int tnum, char *type, int notdata)
|
|
{
|
|
int i, index, something_outside_parens, regfound;
|
|
int parencount;
|
|
char *pt;
|
|
char temp[MAX_TOKEN_LENGTH+1];
|
|
|
|
pt = tokens[tnum];
|
|
|
|
if (pt[0] == '%')
|
|
{
|
|
// register
|
|
for (i=0 ; i<numregs ; i++)
|
|
{
|
|
if (!strcmpi (pt, reglist[i].text))
|
|
{
|
|
printf ("%s", reglist[i].emit);
|
|
return;
|
|
}
|
|
}
|
|
|
|
fprintf (stderr, "Error: bad register %s\n", pt);
|
|
errorexit ();
|
|
}
|
|
else if (pt[0] == '$')
|
|
{
|
|
// constant
|
|
if (pt[1] == '(')
|
|
{
|
|
if ((pt[2] > '9') || (pt[2] < '0'))
|
|
{
|
|
i = 2;
|
|
printf ("offset ");
|
|
|
|
parencount = 1;
|
|
|
|
while ((pt[i] != ')') || (parencount > 1))
|
|
{
|
|
if (!pt[i])
|
|
{
|
|
fprintf (stderr, "mismatched parens");
|
|
errorexit ();
|
|
}
|
|
|
|
if (pt[i] == ')')
|
|
parencount--;
|
|
else if (pt[i] == '(')
|
|
parencount++;
|
|
|
|
printf ("%c", pt[i]);
|
|
i++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pt++;
|
|
|
|
parencount = 1;
|
|
|
|
for (i=1 ; (pt[i] != ')') || (parencount > 1) ; i++)
|
|
{
|
|
if (!pt[i])
|
|
{
|
|
fprintf (stderr, "mismatched parens");
|
|
errorexit ();
|
|
}
|
|
|
|
if (pt[i] == ')')
|
|
parencount--;
|
|
else if (pt[i] == '(')
|
|
parencount++;
|
|
}
|
|
|
|
pt[i] = 0;
|
|
|
|
if ((pt[1] == '0') && ((pt[2] == 'x') || (pt[2] == 'X')))
|
|
{
|
|
printf ("0%sh", &pt[3]);
|
|
}
|
|
else
|
|
{
|
|
printf ("%s", &pt[1]);
|
|
}
|
|
}
|
|
}
|
|
else if ((pt[1] == '0') && ((pt[2] == 'x') || (pt[2] == 'X')))
|
|
{
|
|
printf ("0%sh", &pt[3]);
|
|
}
|
|
else if ((pt[1] >= '0') && (pt[1] <= '9'))
|
|
{
|
|
printf ("%s", &pt[1]);
|
|
}
|
|
else
|
|
{
|
|
printf ("offset %s", &pt[1]);
|
|
}
|
|
}
|
|
else if (!notdata && ((pt[0] >= '0') && (pt[0] <= '9')))
|
|
{
|
|
pt--;
|
|
|
|
if ((pt[1] == '0') && ((pt[2] == 'x') || (pt[2] == 'X')))
|
|
{
|
|
printf ("0%sh", &pt[3]);
|
|
}
|
|
else
|
|
{
|
|
printf ("%s", &pt[1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// must be a memory location
|
|
strcpy (temp, type);
|
|
index = strlen (temp);
|
|
|
|
if (notdata)
|
|
temp[index++] = '[';
|
|
|
|
something_outside_parens = 0;
|
|
|
|
while (*pt)
|
|
{
|
|
if (index > (MAX_TOKEN_LENGTH - 10))
|
|
{
|
|
fprintf (stderr, "Error: operand too long %s\n",
|
|
tokens[tnum]);
|
|
errorexit ();
|
|
}
|
|
|
|
if (*pt != ')')
|
|
{
|
|
if (*pt == '(')
|
|
{
|
|
if (something_outside_parens)
|
|
temp[index++] = '+';
|
|
}
|
|
else if (*pt == '%')
|
|
{
|
|
regfound = 0;
|
|
|
|
for (i=0 ; i<numregs ; i++)
|
|
{
|
|
if (!strnicmp (pt, reglist[i].text,
|
|
reglist[i].len))
|
|
{
|
|
strcpy (&temp[index], reglist[i].emit);
|
|
index += strlen (reglist[i].emit);
|
|
pt += strlen (reglist[i].text) - 1;
|
|
regfound = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!regfound)
|
|
{
|
|
fprintf (stderr, "Error: bad register %s\n", pt);
|
|
errorexit ();
|
|
}
|
|
}
|
|
else if (*pt == ',')
|
|
{
|
|
pt++;
|
|
|
|
if ((*pt >= '1') && (*pt <= '8'))
|
|
{
|
|
temp[index++] = '*';
|
|
temp[index++] = *pt;
|
|
}
|
|
else if (*pt != ')')
|
|
{
|
|
if (temp[index-1] != '+')
|
|
temp[index++] = '+';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
something_outside_parens = 1;
|
|
|
|
// handle hexadecimal constants in addresses
|
|
if ((*pt == '0') &&
|
|
((*(pt+1) == 'x') || (*(pt+1) == 'X')))
|
|
{
|
|
pt += 2;
|
|
|
|
do
|
|
{
|
|
temp[index++] = *pt++;
|
|
} while (((*pt >= '0') && (*pt <= '9')) ||
|
|
((*pt >= 'a') && (*pt <= 'f')) ||
|
|
((*pt >= 'A') && (*pt <= 'F')));
|
|
|
|
pt--;
|
|
temp[index++] = 'h';
|
|
}
|
|
else
|
|
{
|
|
temp[index++] = *pt;
|
|
}
|
|
}
|
|
}
|
|
|
|
pt++;
|
|
}
|
|
|
|
if (notdata)
|
|
temp[index++] = ']';
|
|
|
|
temp[index] = 0;
|
|
printf ("%s", temp);
|
|
}
|
|
}
|
|
|
|
|
|
void datasegstart (void)
|
|
{
|
|
if (currentseg == DATASEG)
|
|
return;
|
|
|
|
if (currentseg == TEXTSEG)
|
|
printf ("_TEXT ENDS\n");
|
|
|
|
printf ("_DATA SEGMENT");
|
|
|
|
currentseg = DATASEG;
|
|
}
|
|
|
|
|
|
void textsegstart (void)
|
|
{
|
|
if (currentseg == TEXTSEG)
|
|
return;
|
|
|
|
if (currentseg == DATASEG)
|
|
printf ("_DATA ENDS\n");
|
|
|
|
printf ("_TEXT SEGMENT");
|
|
|
|
currentseg = TEXTSEG;
|
|
}
|
|
|
|
|
|
void emitdata (void)
|
|
{
|
|
int i;
|
|
|
|
for (i=1 ; i<(tokennum-1) ; i++)
|
|
printf (" %s,", tokens[i]);
|
|
|
|
printf (" %s", tokens[tokennum-1]);
|
|
}
|
|
|
|
|
|
void emitonedata (void)
|
|
{
|
|
|
|
printf (" %s", tokens[1]);
|
|
}
|
|
|
|
|
|
void emitonecalldata (void)
|
|
{
|
|
int i, isaddr, len;
|
|
|
|
if (tokens[1][0] == '*')
|
|
{
|
|
printf (" dword ptr[%s]", &tokens[1][1]);
|
|
}
|
|
else
|
|
{
|
|
isaddr = 0;
|
|
len = strlen(tokens[1]);
|
|
|
|
for (i=0 ; i<len ; i++)
|
|
{
|
|
if (tokens[1][i] == '(')
|
|
{
|
|
isaddr = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isaddr)
|
|
{
|
|
printf (" near ptr %s", tokens[1]);
|
|
}
|
|
else
|
|
{
|
|
emitanoperand (1, " dword ptr", 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void emitonejumpdata (void)
|
|
{
|
|
/*jmp *Ljmptab(,%eax,4)
|
|
jmp dword ptr[Ljmptab(,%eax,4)]
|
|
jmp dword ptr[Ljmptab+eax*4]
|
|
*/
|
|
int i, isaddr, len;
|
|
|
|
isaddr = 0;
|
|
len = strlen(tokens[1]);
|
|
|
|
if (tokens[1][0] == '*') {
|
|
|
|
for (i=0 ; i<len ; i++) {
|
|
if (tokens[1][i] == '(') {
|
|
isaddr = 1;
|
|
break;
|
|
}
|
|
}
|
|
memmove(&tokens[1][0],&tokens[1][1],strlen(tokens[1]));
|
|
if ( !isaddr ) {
|
|
//printf (" dword ptr [%s]", &tokens[1][1]);
|
|
printf (" dword ptr [");
|
|
emitanoperand (1, "", 1);
|
|
printf ("]");
|
|
} else {
|
|
emitanoperand (1, " dword ptr", 1);
|
|
}
|
|
} else {
|
|
|
|
for (i=0 ; i<len ; i++) {
|
|
if (tokens[1][i] == '(') {
|
|
isaddr = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isaddr) {
|
|
printf (" %s", tokens[1]);
|
|
} else {
|
|
emitanoperand (1, " dword ptr", 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void emitexterndef (void)
|
|
{
|
|
printf (" %s:dword", tokens[1]);
|
|
}
|
|
|
|
|
|
void nooperands (void)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
void emitoneoperandl (void)
|
|
{
|
|
|
|
printf (" ");
|
|
emitanoperand (1, "ds:dword ptr", 1);
|
|
}
|
|
|
|
|
|
void emitoneoperandb (void)
|
|
{
|
|
|
|
printf (" ");
|
|
emitanoperand (1, "ds:byte ptr", 1);
|
|
}
|
|
|
|
|
|
void emitoneoperandw (void)
|
|
{
|
|
|
|
printf (" ");
|
|
emitanoperand (1, "ds:word ptr", 1);
|
|
}
|
|
|
|
|
|
void emittwooperandsl (void)
|
|
{
|
|
|
|
printf (" ");
|
|
emitanoperand (2, "ds:dword ptr", 1);
|
|
printf (",");
|
|
emitanoperand (1, "ds:dword ptr", 1);
|
|
}
|
|
|
|
|
|
void emittwooperandsb (void)
|
|
{
|
|
|
|
printf (" ");
|
|
emitanoperand (2, "ds:byte ptr", 1);
|
|
printf (",");
|
|
emitanoperand (1, "ds:byte ptr", 1);
|
|
}
|
|
|
|
|
|
void emittwooperandsw (void)
|
|
{
|
|
|
|
printf (" ");
|
|
emitanoperand (2, "ds:word ptr", 1);
|
|
printf (",");
|
|
emitanoperand (1, "ds:word ptr", 1);
|
|
}
|
|
|
|
|
|
void emit_0_or_1_operandsl (void)
|
|
{
|
|
|
|
if (tokennum == 2)
|
|
{
|
|
printf (" ");
|
|
emitanoperand (1, "ds:dword ptr", 1);
|
|
}
|
|
}
|
|
|
|
|
|
void emit_1_or_2_operandsl (void)
|
|
{
|
|
int j;
|
|
|
|
if (tokennum == 2)
|
|
{
|
|
printf (" ");
|
|
emitanoperand (1, "ds:dword ptr", 1);
|
|
}
|
|
else if (tokennum == 3)
|
|
{
|
|
printf (" ");
|
|
emitanoperand (2, "ds:dword ptr", 1);
|
|
printf (",");
|
|
emitanoperand (1, "ds:dword ptr", 1);
|
|
}
|
|
else
|
|
{
|
|
|
|
fprintf (stderr, "Error: too many operands\n");
|
|
|
|
for (j=0 ; j<tokennum ; j++)
|
|
fprintf (stderr, "%s\n", tokens[j]);
|
|
|
|
fprintf (stderr, "\n");
|
|
errorexit ();
|
|
}
|
|
}
|
|
|
|
|
|
void emit_1_or_2_operandsl_vartext (char *str0, char *str1)
|
|
{
|
|
int j;
|
|
|
|
if (tokennum == 2)
|
|
{
|
|
printf (" %s ", str0);
|
|
emitanoperand (1, "ds:dword ptr", 1);
|
|
}
|
|
else if (tokennum == 3)
|
|
{
|
|
if (!strcmpi (tokens[2], "%st(0)"))
|
|
printf (" %s ", str0);
|
|
else
|
|
printf (" %s ", str1);
|
|
|
|
emitanoperand (2, "ds:dword ptr", 1);
|
|
printf (",");
|
|
emitanoperand (1, "ds:dword ptr", 1);
|
|
}
|
|
else
|
|
{
|
|
|
|
fprintf (stderr, "Error: too many operands\n");
|
|
|
|
for (j=0 ; j<tokennum ; j++)
|
|
fprintf (stderr, "%s\n", tokens[j]);
|
|
|
|
fprintf (stderr, "\n");
|
|
errorexit ();
|
|
}
|
|
}
|
|
|
|
|
|
void special_fdivl (void)
|
|
{
|
|
|
|
emit_1_or_2_operandsl_vartext ("fdiv", "fdivr");
|
|
}
|
|
|
|
|
|
void special_fdivpl (void)
|
|
{
|
|
|
|
emit_1_or_2_operandsl_vartext ("fdivp", "fdivrp");
|
|
}
|
|
|
|
|
|
void special_fdivrl (void)
|
|
{
|
|
|
|
emit_1_or_2_operandsl_vartext ("fdivr", "fdiv");
|
|
}
|
|
|
|
|
|
void special_fdivrpl (void)
|
|
{
|
|
|
|
emit_1_or_2_operandsl_vartext ("fdivrp", "fdivp");
|
|
}
|
|
|
|
|
|
void special_fsubl (void)
|
|
{
|
|
|
|
emit_1_or_2_operandsl_vartext ("fsub", "fsubr");
|
|
}
|
|
|
|
|
|
void special_fsubpl (void)
|
|
{
|
|
|
|
emit_1_or_2_operandsl_vartext ("fsubp", "fsubrp");
|
|
}
|
|
|
|
|
|
void special_fsubrl (void)
|
|
{
|
|
|
|
emit_1_or_2_operandsl_vartext ("fsubr", "fsub");
|
|
}
|
|
|
|
|
|
void special_fsubrpl (void)
|
|
{
|
|
|
|
emit_1_or_2_operandsl_vartext ("fsubrp", "fsubp");
|
|
}
|
|
|
|
|
|
void emit_multiple_data (void)
|
|
{
|
|
int i;
|
|
|
|
printf (" ");
|
|
|
|
for (i=1 ; i<(tokennum-1) ; i++)
|
|
{
|
|
emitanoperand (i, "", 0);
|
|
printf (", ");
|
|
}
|
|
|
|
emitanoperand (i, "", 0);
|
|
}
|
|
|
|
|
|
//==============================================
|
|
|
|
parsefield parsedata[] = {
|
|
{".align", " align", 2, emitonedata},
|
|
{".byte", " db", -2, emit_multiple_data},
|
|
{".data", "", 1, datasegstart},
|
|
{".extern"," externdef", 2, emitexterndef},
|
|
{".globl", " public", -2, emit_multiple_data},
|
|
{".long", " dd", -2, emit_multiple_data},
|
|
{".single"," dd", -2, emit_multiple_data},
|
|
{".text", "", 1, textsegstart},
|
|
{"adcl", " adc", 3, emittwooperandsl},
|
|
{"addb", " add", 3, emittwooperandsb},
|
|
{"addl", " add", 3, emittwooperandsl},
|
|
{"andb", " and", 3, emittwooperandsb},
|
|
{"andl", " and", 3, emittwooperandsl},
|
|
{"call", " call", 2, emitonecalldata},
|
|
{"cmpb", " cmp", 3, emittwooperandsb},
|
|
{"cmpl", " cmp", 3, emittwooperandsl},
|
|
{"cmpw", " cmp", 3, emittwooperandsw},
|
|
{"decl", " dec", 2, emitoneoperandl},
|
|
{"decw", " dec", 2, emitoneoperandw},
|
|
{"divl", " div", 2, emitoneoperandl},
|
|
{"fadd", " fadd", -2, emit_1_or_2_operandsl},
|
|
{"faddp", " faddp", -2, emit_1_or_2_operandsl},
|
|
{"faddps", " faddp", -2, emit_1_or_2_operandsl},
|
|
{"fadds", " fadd", -2, emit_1_or_2_operandsl},
|
|
{"fcom", " fcom", 2, emitoneoperandl},
|
|
{"fcoms", " fcom", 2, emitoneoperandl},
|
|
{"fcomp", " fcomp", 2, emitoneoperandl},
|
|
{"fcomps", " fcomp", 2, emitoneoperandl},
|
|
{"fdiv", "", -2, special_fdivl},
|
|
{"fdivp", "", -2, special_fdivpl},
|
|
{"fdivr", "", -2, special_fdivrl},
|
|
{"fdivrp", "", -2, special_fdivrpl},
|
|
{"fdivrs", "", -2, special_fdivrl},
|
|
{"fildl", " fild", 2, emitoneoperandl},
|
|
{"fistl", " fist", 2, emitoneoperandl},
|
|
{"fistpl", " fistp", 2, emitoneoperandl},
|
|
{"fld", " fld", 2, emitoneoperandl},
|
|
{"fldcw", " fldcw", 2, emitoneoperandw},
|
|
{"fldenv", " fldenv", 2, emitoneoperandl},
|
|
{"flds", " fld", 2, emitoneoperandl},
|
|
{"fmul", " fmul", -2, emit_1_or_2_operandsl},
|
|
{"fmulp", " fmulp", -2, emit_1_or_2_operandsl},
|
|
{"fmulps", " fmulp", -2, emit_1_or_2_operandsl},
|
|
{"fmuls", " fmul", -2, emit_1_or_2_operandsl},
|
|
{"fnstcw", " fnstcw", 2, emitoneoperandw},
|
|
{"fnstenv"," fnstenv", 2, emitoneoperandl},
|
|
{"fnstsw", " fnstsw", 2, emitoneoperandw},
|
|
{"fstp", " fstp", 2, emitoneoperandl},
|
|
{"fstps", " fstp", 2, emitoneoperandl},
|
|
{"fsts", " fst", 2, emitoneoperandl},
|
|
{"fsubr", "", -2, special_fsubrl},
|
|
{"fsubrp", "", -2, special_fsubrpl},
|
|
{"fsubrs", "", -2, special_fsubrl},
|
|
{"fsub", "", -2, special_fsubl},
|
|
{"fsubp", "", -2, special_fsubpl},
|
|
{"fsubps", "", -2, special_fsubpl},
|
|
{"fsubs", "", -2, special_fsubl},
|
|
{"fxch", " fxch", 2, emitoneoperandl},
|
|
{"imull", " imul", -2, emit_1_or_2_operandsl},
|
|
{"incl", " inc", 2, emitoneoperandl},
|
|
{"ja", " ja", 2, emitonedata},
|
|
{"jae", " jae", 2, emitonedata},
|
|
{"jb", " jb", 2, emitonedata},
|
|
{"jbe", " jbe", 2, emitonedata},
|
|
{"jc", " jc", 2, emitonedata},
|
|
{"je", " je", 2, emitonedata},
|
|
{"jg", " jg", 2, emitonedata},
|
|
{"jge", " jge", 2, emitonedata},
|
|
{"jl", " jl", 2, emitonedata},
|
|
{"jle", " jle", 2, emitonedata},
|
|
{"jmp", " jmp", 2, emitonejumpdata},
|
|
{"jna", " jna", 2, emitonedata},
|
|
{"jnae", " jnae", 2, emitonedata},
|
|
{"jnb", " jnb", 2, emitonedata},
|
|
{"jnbe", " jnbe", 2, emitonedata},
|
|
{"jnc", " jnc", 2, emitonedata},
|
|
{"jne", " jne", 2, emitonedata},
|
|
{"jng", " jng", 2, emitonedata},
|
|
{"jnge", " jnge", 2, emitonedata},
|
|
{"jnl", " jnl", 2, emitonedata},
|
|
{"jnle", " jnle", 2, emitonedata},
|
|
{"jns", " jns", 2, emitonedata},
|
|
{"jnz", " jnz", 2, emitonedata},
|
|
{"js", " js", 2, emitonedata},
|
|
{"jz", " jz", 2, emitonedata},
|
|
{"leal", " lea", 3, emittwooperandsl},
|
|
{"movb", " mov", 3, emittwooperandsb},
|
|
{"movl", " mov", 3, emittwooperandsl},
|
|
{"movw", " mov", 3, emittwooperandsw},
|
|
{"negl", " neg", 2, emitoneoperandl},
|
|
{"orb", " or", 3, emittwooperandsb},
|
|
{"orl", " or", 3, emittwooperandsl},
|
|
{"popl", " pop", 2, emitoneoperandl},
|
|
{"pushl", " push", 2, emitoneoperandl},
|
|
{"ret", " ret", -1, emit_0_or_1_operandsl},
|
|
{"rorl", " ror", 3, emittwooperandsl},
|
|
{"sarl", " sar", 3, emittwooperandsl},
|
|
{"sbbl", " sbb", 3, emittwooperandsl},
|
|
{"shll", " shl", 3, emittwooperandsl},
|
|
{"shrl", " shr", 3, emittwooperandsl},
|
|
{"subl", " sub", 3, emittwooperandsl},
|
|
{"testb", " test", 3, emittwooperandsb},
|
|
{"testl", " test", 3, emittwooperandsl},
|
|
{"xorb", " xor", 3, emittwooperandsb},
|
|
{"xorl", " xor", 3, emittwooperandsl},
|
|
};
|
|
|
|
int numparse = sizeof (parsedata) / sizeof (parsedata[0]);
|
|
|
|
//==============================================
|
|
|
|
void errorexit (void)
|
|
{
|
|
fprintf (stderr, "In line: %d, out line: %d\n", linein, lineout);
|
|
exit (1);
|
|
}
|
|
|
|
|
|
tokenstat whitespace (int c)
|
|
{
|
|
if (c == '\n')
|
|
return LINE_DONE;
|
|
|
|
if ((c <= ' ') ||
|
|
//(c > 127) ||
|
|
(c == ','))
|
|
{
|
|
return WHITESPACE;
|
|
}
|
|
|
|
return NOT_WHITESPACE;
|
|
}
|
|
|
|
|
|
int gettoken (void)
|
|
{
|
|
int c;
|
|
int count, parencount;
|
|
tokenstat stat;
|
|
|
|
do
|
|
{
|
|
if ((c = getchar ()) == EOF)
|
|
return FILE_DONE;
|
|
|
|
if ((stat = whitespace (c)) == LINE_DONE)
|
|
return LINE_DONE;
|
|
} while (stat == WHITESPACE);
|
|
|
|
if (c == '#')
|
|
{
|
|
do
|
|
{
|
|
if ((c = getchar()) == EOF)
|
|
return FILE_DONE;
|
|
} while (whitespace(c) != LINE_DONE);
|
|
|
|
return LINE_DONE;
|
|
}
|
|
|
|
|
|
token[0] = c;
|
|
count = 1;
|
|
|
|
if (c == '~')
|
|
{
|
|
count--;
|
|
token[count++] = 'n';
|
|
token[count++] = 'o';
|
|
token[count++] = 't';
|
|
token[count++] = ' ';
|
|
}
|
|
|
|
if (c == '(')
|
|
{
|
|
do
|
|
{
|
|
if ((c = getchar ()) == EOF)
|
|
{
|
|
fprintf (stderr, "EOF in middle of parentheses\n");
|
|
errorexit ();
|
|
}
|
|
|
|
token[count++] = c;
|
|
|
|
} while (c != ')');
|
|
}
|
|
|
|
for ( ;; )
|
|
{
|
|
if ((c = getchar ()) == EOF)
|
|
{
|
|
token[count] = 0;
|
|
return TOKEN_AVAILABLE;
|
|
}
|
|
|
|
if (whitespace (c) == LINE_DONE)
|
|
{
|
|
if (ungetc (c, stdin) == EOF)
|
|
{
|
|
fprintf (stderr, "Couldn't unget character\n");
|
|
errorexit ();
|
|
}
|
|
|
|
token[count] = 0;
|
|
return TOKEN_AVAILABLE;
|
|
}
|
|
|
|
if (whitespace (c) == WHITESPACE)
|
|
{
|
|
token[count] = 0;
|
|
return TOKEN_AVAILABLE;
|
|
}
|
|
|
|
if (count >= MAX_TOKEN_LENGTH)
|
|
{
|
|
fprintf (stderr, "Error: token too long\n");
|
|
errorexit ();
|
|
}
|
|
|
|
token[count++] = c;
|
|
|
|
if (c == '~')
|
|
{
|
|
count--;
|
|
token[count++] = 'n';
|
|
token[count++] = 'o';
|
|
token[count++] = 't';
|
|
token[count++] = ' ';
|
|
}
|
|
else if (c == '(')
|
|
{
|
|
parencount = 1;
|
|
|
|
do
|
|
{
|
|
if ((c = getchar ()) == EOF)
|
|
{
|
|
fprintf (stderr, "EOF in middle of parentheses\n");
|
|
errorexit ();
|
|
}
|
|
|
|
if (c == '(')
|
|
parencount++;
|
|
else if (c == ')')
|
|
parencount--;
|
|
|
|
if (c == '~')
|
|
{
|
|
token[count++] = 'n';
|
|
token[count++] = 'o';
|
|
token[count++] = 't';
|
|
token[count++] = ' ';
|
|
}
|
|
else
|
|
{
|
|
token[count++] = c;
|
|
}
|
|
|
|
} while ((c != ')') || (parencount > 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
tokenstat parseline (void)
|
|
{
|
|
tokenstat stat;
|
|
int i, j, firsttoken, labelfound;
|
|
int mnemfound;
|
|
|
|
firsttoken = 1;
|
|
tokennum = 0;
|
|
labelfound = 0;
|
|
|
|
for ( ;; )
|
|
{
|
|
token = tokens[tokennum];
|
|
stat = gettoken ();
|
|
|
|
switch (stat)
|
|
{
|
|
case FILE_DONE:
|
|
return FILE_DONE;
|
|
|
|
case LINE_DONE:
|
|
if (!firsttoken && tokennum)
|
|
{
|
|
mnemfound = 0;
|
|
|
|
for (i=0 ; i<numparse; i++)
|
|
{
|
|
if (!strcmpi (tokens[0], parsedata[i].text))
|
|
{
|
|
if (((parsedata[i].numtokens > 0) &&
|
|
(parsedata[i].numtokens != tokennum)) ||
|
|
((parsedata[i].numtokens < 0) &&
|
|
(tokennum < -parsedata[i].numtokens)))
|
|
{
|
|
fprintf (stderr, "mismatched number of tokens\n");
|
|
|
|
for (j=0 ; j<tokennum ; j++)
|
|
fprintf (stderr, "%s\n", tokens[j]);
|
|
|
|
fprintf (stderr, "\n");
|
|
errorexit ();
|
|
}
|
|
|
|
printf ("%s", parsedata[i].emit);
|
|
(*parsedata[i].parsefunc) ();
|
|
|
|
mnemfound = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!mnemfound)
|
|
{
|
|
fprintf (stderr, "Error: unknown mnemonic\n");
|
|
|
|
for (j=0 ; j<tokennum ; j++)
|
|
fprintf (stderr, "%s\n", tokens[j]);
|
|
|
|
fprintf (stderr, "\n");
|
|
errorexit ();
|
|
}
|
|
}
|
|
|
|
if (!firsttoken)
|
|
{
|
|
if ((currentseg == DATASEG) && labelfound && !tokennum)
|
|
printf (":\n");
|
|
else
|
|
printf ("\n");
|
|
|
|
lineout++;
|
|
}
|
|
return PARSED_OKAY;
|
|
|
|
case TOKEN_AVAILABLE:
|
|
if (firsttoken)
|
|
{
|
|
if (token[strlen(token) - 1] == ':')
|
|
{
|
|
labelfound = 1;
|
|
|
|
if (currentseg == DATASEG)
|
|
{
|
|
token[strlen(token) - 1] = 0;
|
|
printf ("%s", token);
|
|
}
|
|
else if (currentseg == TEXTSEG)
|
|
{
|
|
printf ("%s", token);
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr, "Error: not in segment block\n");
|
|
errorexit ();
|
|
}
|
|
|
|
firsttoken = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
firsttoken = 0;
|
|
|
|
if (tokennum >= MAX_TOKENS)
|
|
{
|
|
fprintf (stderr, "Error: too many tokens\n");
|
|
exit (0);
|
|
}
|
|
|
|
tokennum++;
|
|
|
|
break;
|
|
|
|
default:
|
|
fprintf (stderr, "Error: unknown tokenstat %d\n", stat);
|
|
exit (0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int main ()
|
|
{
|
|
tokenstat stat;
|
|
|
|
printf (" .386P\n"
|
|
" .model FLAT\n");
|
|
linein = 1;
|
|
lineout = 3;
|
|
|
|
for ( ;; )
|
|
{
|
|
stat = parseline ();
|
|
linein++;
|
|
|
|
switch (stat)
|
|
{
|
|
case FILE_DONE:
|
|
if (currentseg == TEXTSEG)
|
|
printf ("_TEXT ENDS\n");
|
|
else if (currentseg == DATASEG)
|
|
printf ("_DATA ENDS\n");
|
|
|
|
printf (" END\n");
|
|
return 0;
|
|
|
|
case PARSED_OKAY:
|
|
break;
|
|
|
|
default:
|
|
fprintf (stderr, "Error: unknown tokenstat %d\n", stat);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|