Initial commit.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
|
||||
#ifndef ASSEM_H
|
||||
#define ASSEM_H
|
||||
|
||||
#include "..\linker\linker.h"
|
||||
|
||||
class Assem{
|
||||
public:
|
||||
istream ∈
|
||||
Module *mod;
|
||||
Assem( istream &in,Module *mod ):in( in ),mod( mod ){}
|
||||
virtual void assemble()=0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,585 @@
|
||||
//
|
||||
//This is generated code - do not modify!!!!!
|
||||
//
|
||||
|
||||
#include "..\std.h"
|
||||
|
||||
|
||||
#include "insts.h"
|
||||
|
||||
Inst insts[]={
|
||||
"aaa",NONE,NONE,0,"\x1\x37",
|
||||
"aas",NONE,NONE,0,"\x1\x3F",
|
||||
"aad",NONE,NONE,0,"\x2\xD5\x0A",
|
||||
0,IMM,NONE,IB,"\x1\xD5",
|
||||
"aam",NONE,NONE,0,"\x2\xD4\x0A",
|
||||
0,IMM,NONE,IB,"\x1\xD4",
|
||||
"adc",AL,IMM8,IB,"\x1\x14",
|
||||
0,AX,IMM16,O16|IW,"\x1\x15",
|
||||
0,EAX,IMM32,O32|ID,"\x1\x15",
|
||||
0,R_M8,REG8,_R,"\x1\x10",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x11",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x11",
|
||||
0,REG8,R_M8,_R,"\x1\x12",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x13",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x13",
|
||||
0,R_M8,IMM8,_2|IB,"\x1\x80",
|
||||
0,R_M16,IMM16,O16|_2|IW,"\x1\x81",
|
||||
0,R_M32,IMM32,O32|_2|ID,"\x1\x81",
|
||||
0,R_M16,IMM8,O16|_2|IB,"\x1\x83",
|
||||
0,R_M32,IMM8,O32|_2|IB,"\x1\x83",
|
||||
"add",AL,IMM8,IB,"\x1\x04",
|
||||
0,AX,IMM16,O16|IW,"\x1\x05",
|
||||
0,EAX,IMM32,O32|ID,"\x1\x05",
|
||||
0,R_M8,REG8,_R,"\x1\x00",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x01",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x01",
|
||||
0,REG8,R_M8,_R,"\x1\x02",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x03",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x03",
|
||||
0,R_M8,IMM8,_0|IB,"\x1\x80",
|
||||
0,R_M16,IMM16,O16|_0|IW,"\x1\x81",
|
||||
0,R_M32,IMM32,O32|_0|ID,"\x1\x81",
|
||||
0,R_M16,IMM8,O16|_0|IB,"\x1\x83",
|
||||
0,R_M32,IMM8,O32|_0|IB,"\x1\x83",
|
||||
"and",AL,IMM8,IB,"\x1\x24",
|
||||
0,AX,IMM16,O16|IW,"\x1\x25",
|
||||
0,EAX,IMM32,O32|ID,"\x1\x25",
|
||||
0,R_M8,REG8,_R,"\x1\x20",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x21",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x21",
|
||||
0,REG8,R_M8,_R,"\x1\x22",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x23",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x23",
|
||||
0,R_M8,IMM8,_4|IB,"\x1\x80",
|
||||
0,R_M16,IMM16,O16|_4|IW,"\x1\x81",
|
||||
0,R_M32,IMM32,O32|_4|ID,"\x1\x81",
|
||||
0,R_M16,IMM8,O16|_4|IB,"\x1\x83",
|
||||
0,R_M32,IMM8,O32|_4|IB,"\x1\x83",
|
||||
"arpl",R_M16,REG16,_R,"\x1\x63",
|
||||
"bound",REG16,MEM,O16|_R,"\x1\x62",
|
||||
0,REG32,MEM,O32|_R,"\x1\x62",
|
||||
"bsf",REG16,R_M16,O16|_R,"\x2\x0F\xBC",
|
||||
0,REG32,R_M32,O32|_R,"\x2\x0F\xBC",
|
||||
"bsr",REG16,R_M16,O16|_R,"\x2\x0F\xBD",
|
||||
0,REG32,R_M32,O32|_R,"\x2\x0F\xBD",
|
||||
"bswap",REG32,NONE,O32|PLUSREG,"\x2\x0F\xC8",
|
||||
"bt",R_M16,REG16,O16|_R,"\x2\x0F\xA3",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\xA3",
|
||||
0,R_M16,IMM8,O16|_4|IB,"\x2\x0F\xBA",
|
||||
0,R_M32,IMM8,O32|_4|IB,"\x2\x0F\xBA",
|
||||
"btc",R_M16,REG16,O16|_R,"\x2\x0F\xBB",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\xBB",
|
||||
0,R_M16,IMM8,O16|_7|IB,"\x2\x0F\xBA",
|
||||
0,R_M32,IMM8,O32|_7|IB,"\x2\x0F\xBA",
|
||||
"btr",R_M16,REG16,O16|_R,"\x2\x0F\xB3",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\xB3",
|
||||
0,R_M16,IMM8,O16|_6|IB,"\x2\x0F\xBA",
|
||||
0,R_M32,IMM8,O32|_6|IB,"\x2\x0F\xBA",
|
||||
"bts",R_M16,REG16,O16|_R,"\x2\x0F\xAB",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\xAB",
|
||||
0,R_M16,IMM,O16|_5|IB,"\x2\x0F\xBA",
|
||||
0,R_M32,IMM,O32|_5|IB,"\x2\x0F\xBA",
|
||||
"call",IMM,NONE,RW_RD,"\x1\xE8",
|
||||
0,R_M16,NONE,O16|_2,"\x1\xFF",
|
||||
0,R_M32,NONE,O32|_2,"\x1\xFF",
|
||||
"cbw",NONE,NONE,O16,"\x1\x98",
|
||||
"cwd",NONE,NONE,O16,"\x1\x99",
|
||||
"cdq",NONE,NONE,O32,"\x1\x99",
|
||||
"cwde",NONE,NONE,O32,"\x1\x98",
|
||||
"clc",NONE,NONE,0,"\x1\xF8",
|
||||
"cld",NONE,NONE,0,"\x1\xFC",
|
||||
"cli",NONE,NONE,0,"\x1\xFA",
|
||||
"clts",NONE,NONE,0,"\x2\x0F\x06",
|
||||
"cmc",NONE,NONE,0,"\x1\xF5",
|
||||
"cmovcc",REG16,R_M16,O16|PLUSCC|_R,"\x2\x0F\x40",
|
||||
0,REG32,R_M32,O32|PLUSCC|_R,"\x2\x0F\x40",
|
||||
"cmp",AL,IMM8,IB,"\x1\x3C",
|
||||
0,AX,IMM16,O16|IW,"\x1\x3D",
|
||||
0,EAX,IMM32,O32|ID,"\x1\x3D",
|
||||
0,R_M8,REG8,_R,"\x1\x38",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x39",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x39",
|
||||
0,REG8,R_M8,_R,"\x1\x3A",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x3B",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x3B",
|
||||
0,R_M8,IMM8,_7|IB,"\x1\x80",
|
||||
0,R_M16,IMM16,O16|_7|IW,"\x1\x81",
|
||||
0,R_M32,IMM32,O32|_7|ID,"\x1\x81",
|
||||
0,R_M16,IMM8,O16|_7|IB,"\x1\x83",
|
||||
0,R_M32,IMM8,O32|_7|IB,"\x1\x83",
|
||||
"cmpsb",NONE,NONE,0,"\x1\xA6",
|
||||
"cmpsw",NONE,NONE,O16,"\x1\xA7",
|
||||
"cmpsd",NONE,NONE,O32,"\x1\xA7",
|
||||
"cmpxchg",R_M8,REG8,_R,"\x2\x0F\xB0",
|
||||
0,R_M16,REG16,O16|_R,"\x2\x0F\xB1",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\xB1",
|
||||
"cmpxchg486",R_M8,REG8,_R,"\x2\x0F\xA6",
|
||||
0,R_M16,REG16,O16|_R,"\x2\x0F\xA7",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\xA7",
|
||||
"cmpxchg8b",MEM,NONE,_1,"\x2\x0F\xC7",
|
||||
"cpuid",NONE,NONE,0,"\x2\x0F\xA2",
|
||||
"daa",NONE,NONE,0,"\x1\x27",
|
||||
"das",NONE,NONE,0,"\x1\x2F",
|
||||
"dec",REG16,NONE,O16|PLUSREG,"\x1\x48",
|
||||
0,REG32,NONE,O32|PLUSREG,"\x1\x48",
|
||||
0,R_M8,NONE,_1,"\x1\xFE",
|
||||
0,R_M16,NONE,O16|_1,"\x1\xFF",
|
||||
0,R_M32,NONE,O32|_1,"\x1\xFF",
|
||||
"div",R_M8,NONE,_6,"\x1\xF6",
|
||||
0,R_M16,NONE,O16|_6,"\x1\xF7",
|
||||
0,R_M32,NONE,O32|_6,"\x1\xF7",
|
||||
"emms",NONE,NONE,0,"\x2\x0F\x77",
|
||||
"enter",IMM,IMM,IW|IB,"\x1\xC8",
|
||||
"f2xm1",NONE,NONE,0,"\x2\xD9\xF0",
|
||||
"fabs",NONE,NONE,0,"\x2\xD9\xE1",
|
||||
"fadd",MEM32,NONE,_0,"\x1\xD8",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD8\xC0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD8\xC0",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDC\xC0",
|
||||
"faddp",FPUREG,NONE,PLUSREG,"\x2\xDE\xC0",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDE\xC0",
|
||||
"fchs",NONE,NONE,0,"\x2\xD9\xE0",
|
||||
"fclex",NONE,NONE,0,"\x4\x9B\xDB\xE2",
|
||||
"fnclex",NONE,NONE,0,"\x2\xDB\xE2",
|
||||
"fcmovb",FPUREG,NONE,PLUSREG,"\x2\xDA\xC0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDA\xC0",
|
||||
"fcmovbe",FPUREG,NONE,PLUSREG,"\x2\xDA\xD0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDA\xD0",
|
||||
"fcmove",FPUREG,NONE,PLUSREG,"\x2\xDA\xC8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDA\xC8",
|
||||
"fcmovnb",FPUREG,NONE,PLUSREG,"\x2\xDB\xC0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDB\xC0",
|
||||
"fcmovnbe",FPUREG,NONE,PLUSREG,"\x2\xDB\xD0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDB\xD0",
|
||||
"fcmovne",FPUREG,NONE,PLUSREG,"\x2\xDB\xC8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDB\xC8",
|
||||
"fcmovnu",FPUREG,NONE,PLUSREG,"\x2\xDB\xD8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDB\xD8",
|
||||
"fcmovu",FPUREG,NONE,PLUSREG,"\x2\xDA\xD8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDA\xD8",
|
||||
"fcom",MEM32,NONE,_2,"\x1\xD8",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD8\xD0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD8\xD0",
|
||||
"fcomp",MEM32,NONE,_3,"\x1\xD8",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD8\xD8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD8\xD8",
|
||||
"fcompp",NONE,NONE,0,"\x2\xDE\xD9",
|
||||
"fcomi",FPUREG,NONE,PLUSREG,"\x2\xDB\xF0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDB\xF0",
|
||||
"fcomip",FPUREG,NONE,PLUSREG,"\x2\xDF\xF0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDF\xF0",
|
||||
"fcos",NONE,NONE,0,"\x2\xD9\xFF",
|
||||
"fdecstp",NONE,NONE,0,"\x2\xD9\xF6",
|
||||
"fdisi",NONE,NONE,0,"\x4\x9B\xDB\xE1",
|
||||
"fndisi",NONE,NONE,0,"\x2\xDB\xE1",
|
||||
"feni",NONE,NONE,0,"\x4\x9B\xDB\xE0",
|
||||
"fneni",NONE,NONE,0,"\x2\xDB\xE0",
|
||||
"fdiv",MEM32,NONE,_6,"\x1\xD8",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD8\xF0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD8\xF0",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDC\xF8",
|
||||
"fdivr",MEM32,NONE,_0,"\x1\xD8",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD8\xF8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD8\xF8",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDC\xF0",
|
||||
"fdivp",FPUREG,NONE,PLUSREG,"\x2\xDE\xF8",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDE\xF8",
|
||||
"fdivrp",FPUREG,NONE,PLUSREG,"\x2\xDE\xF0",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDE\xF0",
|
||||
"ffree",FPUREG,NONE,PLUSREG,"\x2\xDD\xC0",
|
||||
"fiadd",MEM16,NONE,_0,"\x1\xDE",
|
||||
0,MEM32,NONE,_0,"\x1\xDA",
|
||||
"ficom",MEM16,NONE,_2,"\x1\xDE",
|
||||
0,MEM32,NONE,_2,"\x1\xDA",
|
||||
"ficomp",MEM16,NONE,_3,"\x1\xDE",
|
||||
0,MEM32,NONE,_3,"\x1\xDA",
|
||||
"fidiv",MEM16,NONE,_6,"\x1\xDE",
|
||||
0,MEM32,NONE,_6,"\x1\xDA",
|
||||
"fidivr",MEM16,NONE,_0,"\x1\xDE",
|
||||
0,MEM32,NONE,_0,"\x1\xDA",
|
||||
"fild",MEM16,NONE,_0,"\x1\xDF",
|
||||
0,MEM32,NONE,_0,"\x1\xDB",
|
||||
"fist",MEM16,NONE,_2,"\x1\xDF",
|
||||
0,MEM32,NONE,_2,"\x1\xDB",
|
||||
"fistp",MEM16,NONE,_3,"\x1\xDF",
|
||||
0,MEM32,NONE,_3,"\x1\xDB",
|
||||
"fimul",MEM16,NONE,_1,"\x1\xDE",
|
||||
0,MEM32,NONE,_1,"\x1\xDA",
|
||||
"fincstp",NONE,NONE,0,"\x2\xD9\xF7",
|
||||
"finit",NONE,NONE,0,"\x4\x9B\xDB\xE3",
|
||||
"fninit",NONE,NONE,0,"\x2\xDB\xE3",
|
||||
"fisub",MEM16,NONE,_4,"\x1\xDE",
|
||||
0,MEM32,NONE,_4,"\x1\xDA",
|
||||
"fisubr",MEM16,NONE,_5,"\x1\xDE",
|
||||
0,MEM32,NONE,_5,"\x1\xDA",
|
||||
"fld",MEM32,NONE,_0,"\x1\xD9",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD9\xC0",
|
||||
"fld1",NONE,NONE,0,"\x2\xD9\xE8",
|
||||
"fldl2e",NONE,NONE,0,"\x2\xD9\xEA",
|
||||
"fldl2t",NONE,NONE,0,"\x2\xD9\xE9",
|
||||
"fldlg2",NONE,NONE,0,"\x2\xD9\xEC",
|
||||
"fldln2",NONE,NONE,0,"\x2\xD9\xED",
|
||||
"fldpi",NONE,NONE,0,"\x2\xD9\xEB",
|
||||
"fldz",NONE,NONE,0,"\x2\xD9\xEE",
|
||||
"fldcw",MEM16,NONE,_5,"\x1\xD9",
|
||||
"fldenv",MEM,NONE,_4,"\x1\xD9",
|
||||
"fmul",MEM32,NONE,_1,"\x1\xD8",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD8\xC8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD8\xC8",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDC\xC8",
|
||||
"fmulp",FPUREG,NONE,PLUSREG,"\x2\xDE\xC8",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDE\xC8",
|
||||
"fnop",NONE,NONE,0,"\x2\xD9\xD0",
|
||||
"fpatan",NONE,NONE,0,"\x2\xD9\xF3",
|
||||
"fptan",NONE,NONE,0,"\x2\xD9\xF2",
|
||||
"fprem",NONE,NONE,0,"\x2\xD9\xF8",
|
||||
"fprem1",NONE,NONE,0,"\x2\xD9\xF5",
|
||||
"frndint",NONE,NONE,0,"\x2\xD9\xFC",
|
||||
"fsave",MEM,NONE,_6,"\x2\x9B\xDD",
|
||||
"fnsave",MEM,NONE,_6,"\x1\xDD",
|
||||
"frstor",MEM,NONE,_4,"\x1\xDD",
|
||||
"fscale",NONE,NONE,0,"\x2\xD9\xFD",
|
||||
"fsetpm",NONE,NONE,0,"\x2\xDB\xE4",
|
||||
"fsin",NONE,NONE,0,"\x2\xD9\xFE",
|
||||
"fsincos",NONE,NONE,0,"\x2\xD9\xFB",
|
||||
"fsqrt",NONE,NONE,0,"\x2\xD9\xFA",
|
||||
"fst",MEM32,NONE,_2,"\x1\xD9",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xDD\xD0",
|
||||
"fstp",MEM32,NONE,_3,"\x1\xD9",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xDD\xD8",
|
||||
"fstcw",MEM16,NONE,_0,"\x2\x9B\xD9",
|
||||
"fnstcw",MEM16,NONE,_0,"\x1\xD9",
|
||||
"fstenv",MEM,NONE,_6,"\x2\x9B\xD9",
|
||||
"fnstenv",MEM,NONE,_6,"\x1\xD9",
|
||||
"fstsw",MEM16,NONE,_0,"\x2\x9B\xDD",
|
||||
0,AX,NONE,0,"\x4\x9B\xDF\xE0",
|
||||
"fnstsw",MEM16,NONE,_0,"\x1\xDD",
|
||||
0,AX,NONE,0,"\x2\xDF\xE0",
|
||||
"fsub",MEM32,NONE,_4,"\x1\xD8",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD8\xE0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD8\xE0",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDC\xE8",
|
||||
"fsubr",MEM32,NONE,_5,"\x1\xD8",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD8\xE8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD8\xE8",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDC\xE0",
|
||||
"fsubp",FPUREG,NONE,PLUSREG,"\x2\xDE\xE8",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDE\xE8",
|
||||
"fsubrp",FPUREG,NONE,PLUSREG,"\x2\xDE\xE0",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xDE\xE0",
|
||||
"ftst",NONE,NONE,0,"\x2\xD9\xE4",
|
||||
"fucom",FPUREG,NONE,PLUSREG,"\x2\xDD\xE0",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDD\xE0",
|
||||
"fucomp",FPUREG,NONE,PLUSREG,"\x2\xDD\xE8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDD\xE8",
|
||||
"fucompp",NONE,NONE,0,"\x2\xDA\xE9",
|
||||
"fucomi",FPUREG,NONE,PLUSREG,"\x2\xDB\xE8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDB\xE8",
|
||||
"fucomip",FPUREG,NONE,PLUSREG,"\x2\xDF\xE8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xDF\xE8",
|
||||
"fxam",NONE,NONE,0,"\x2\xD9\xE5",
|
||||
"fxch",NONE,NONE,0,"\x2\xD9\xC9",
|
||||
0,FPUREG,NONE,PLUSREG,"\x2\xD9\xC8",
|
||||
0,FPUREG,ST0,PLUSREG,"\x2\xD9\xC8",
|
||||
0,ST0,FPUREG,PLUSREG,"\x2\xD9\xC8",
|
||||
"fxtract",NONE,NONE,0,"\x2\xD9\xF4",
|
||||
"fyl2x",NONE,NONE,0,"\x2\xD9\xF1",
|
||||
"fyl2xp1",NONE,NONE,0,"\x2\xD9\xF9",
|
||||
"hlt",NONE,NONE,0,"\x1\xF4",
|
||||
"ibts",R_M16,REG16,O16|_R,"\x2\x0F\xA7",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\xA7",
|
||||
"idiv",R_M8,NONE,_7,"\x1\xF6",
|
||||
0,R_M16,NONE,O16|_7,"\x1\xF7",
|
||||
0,R_M32,NONE,O32|_7,"\x1\xF7",
|
||||
"imul",R_M8,NONE,_5,"\x1\xF6",
|
||||
0,R_M16,NONE,O16|_5,"\x1\xF7",
|
||||
0,R_M32,NONE,O32|_5,"\x1\xF7",
|
||||
0,REG16,R_M16,O16|_R,"\x2\x0F\xAF",
|
||||
0,REG32,R_M32,O32|_R,"\x2\x0F\xAF",
|
||||
0,REG16,IMM8,O16|_R|IB,"\x1\x6B",
|
||||
0,REG16,IMM16,O16|_R|IW,"\x1\x69",
|
||||
0,REG32,IMM8,O32|_R|IB,"\x1\x6B",
|
||||
0,REG32,IMM32,O32|_R|ID,"\x1\x69",
|
||||
"in",AL,IMM8,IB,"\x1\xE4",
|
||||
0,AX,IMM8,O16|IB,"\x1\xE5",
|
||||
0,EAX,IMM8,O32|IB,"\x1\xE5",
|
||||
"inc",REG16,NONE,O16|PLUSREG,"\x1\x40",
|
||||
0,REG32,NONE,O32|PLUSREG,"\x1\x40",
|
||||
0,R_M8,NONE,_0,"\x1\xFE",
|
||||
0,R_M16,NONE,O16|_0,"\x1\xFF",
|
||||
0,R_M32,NONE,O32|_0,"\x1\xFF",
|
||||
"insb",NONE,NONE,0,"\x1\x6C",
|
||||
"insw",NONE,NONE,O16,"\x1\x6D",
|
||||
"insd",NONE,NONE,O32,"\x1\x6D",
|
||||
"int",IMM8,NONE,IB,"\x1\xCD",
|
||||
"int1",NONE,NONE,0,"\x1\xF1",
|
||||
"icebp",NONE,NONE,0,"\x1\xF1",
|
||||
"int01",NONE,NONE,0,"\x1\xF1",
|
||||
"int3",NONE,NONE,0,"\x1\xCC",
|
||||
"into",NONE,NONE,0,"\x1\xCE",
|
||||
"invd",NONE,NONE,0,"\x2\x0F\x08",
|
||||
"invlpg",MEM,NONE,_0,"\x2\x0F\x01",
|
||||
"iret",NONE,NONE,0,"\x1\xCF",
|
||||
"iretw",NONE,NONE,O16,"\x1\xCF",
|
||||
"iretd",NONE,NONE,O32,"\x1\xCF",
|
||||
"jmp",IMM,NONE,RW_RD,"\x1\xE9",
|
||||
0,R_M16,NONE,O16|_4,"\x1\xFF",
|
||||
0,R_M32,NONE,O32|_4,"\x1\xFF",
|
||||
"lahf",NONE,NONE,0,"\x1\x9F",
|
||||
"lar",REG16,R_M16,O16|_R,"\x2\x0F\x02",
|
||||
0,REG32,R_M32,O32|_R,"\x2\x0F\x02",
|
||||
"lds",REG16,MEM,O16|_R,"\x1\xC5",
|
||||
0,REG32,MEM,O32|_R,"\x1\xC5",
|
||||
"les",REG16,MEM,O16|_R,"\x1\xC4",
|
||||
0,REG32,MEM,O32|_R,"\x1\xC4",
|
||||
"lfs",REG16,MEM,O16|_R,"\x2\x0F\xB4",
|
||||
0,REG32,MEM,O32|_R,"\x2\x0F\xB4",
|
||||
"lgs",REG16,MEM,O16|_R,"\x2\x0F\xB5",
|
||||
0,REG32,MEM,O32|_R,"\x2\x0F\xB5",
|
||||
"lss",REG16,MEM,O16|_R,"\x2\x0F\xB2",
|
||||
0,REG32,MEM,O32|_R,"\x2\x0F\xB2",
|
||||
"lea",REG16,MEM,O16|_R,"\x1\x8D",
|
||||
0,REG32,MEM,O32|_R,"\x1\x8D",
|
||||
"leave",NONE,NONE,0,"\x1\xC9",
|
||||
"lgdt",MEM,NONE,_2,"\x2\x0F\x01",
|
||||
"lidt",MEM,NONE,_3,"\x2\x0F\x01",
|
||||
"lldt",R_M16,NONE,_2,"\x2\x0F\x00",
|
||||
"lmsw",R_M16,NONE,_6,"\x2\x0F\x01",
|
||||
"loadall",NONE,NONE,0,"\x2\x0F\x07",
|
||||
"loadall286",NONE,NONE,0,"\x2\x0F\x05",
|
||||
"lodsb",NONE,NONE,0,"\x1\xAC",
|
||||
"lodsw",NONE,NONE,O16,"\x1\xAD",
|
||||
"lodsd",NONE,NONE,O32,"\x1\xAD",
|
||||
"lsl",REG16,R_M16,O16|_R,"\x2\x0F\x03",
|
||||
0,REG32,R_M32,O32|_R,"\x2\x0F\x03",
|
||||
"ltr",R_M16,NONE,_3,"\x2\x0F\x00",
|
||||
"mov",R_M8,REG8,_R,"\x1\x88",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x89",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x89",
|
||||
0,REG8,R_M8,_R,"\x1\x8A",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x8B",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x8B",
|
||||
0,REG8,IMM8,PLUSREG|IB,"\x1\xB0",
|
||||
0,REG16,IMM16,O16|PLUSREG|IW,"\x1\xB8",
|
||||
0,REG32,IMM32,O32|PLUSREG|ID,"\x1\xB8",
|
||||
0,R_M8,IMM8,_0|IB,"\x1\xC6",
|
||||
0,R_M16,IMM16,O16|_0|IW,"\x1\xC7",
|
||||
0,R_M32,IMM32,O32|_0|ID,"\x1\xC7",
|
||||
"movsb",NONE,NONE,0,"\x1\xA4",
|
||||
"movsw",NONE,NONE,O16,"\x1\xA5",
|
||||
"movsd",NONE,NONE,O32,"\x1\xA5",
|
||||
"movsx",REG16,R_M8,O16|_R,"\x2\x0F\xBE",
|
||||
0,REG32,R_M8,O32|_R,"\x2\x0F\xBE",
|
||||
0,REG32,R_M16,O32|_R,"\x2\x0F\xBF",
|
||||
"movzx",REG16,R_M8,O16|_R,"\x2\x0F\xB6",
|
||||
0,REG32,R_M8,O32|_R,"\x2\x0F\xB6",
|
||||
0,REG32,R_M16,O32|_R,"\x2\x0F\xB7",
|
||||
"mul",R_M8,NONE,_4,"\x1\xF6",
|
||||
0,R_M16,NONE,O16|_4,"\x1\xF7",
|
||||
0,R_M32,NONE,O32|_4,"\x1\xF7",
|
||||
"neg",R_M8,NONE,_3,"\x1\xF6",
|
||||
0,R_M16,NONE,O16|_3,"\x1\xF7",
|
||||
0,R_M32,NONE,O32|_3,"\x1\xF7",
|
||||
"not",R_M8,NONE,_2,"\x1\xF6",
|
||||
0,R_M16,NONE,O16|_2,"\x1\xF7",
|
||||
0,R_M32,NONE,O32|_2,"\x1\xF7",
|
||||
"nop",NONE,NONE,0,"\x1\x90",
|
||||
"or",AL,IMM8,IB,"\x1\x0C",
|
||||
0,AX,IMM16,O16|IW,"\x1\x0D",
|
||||
0,EAX,IMM32,O32|ID,"\x1\x0D",
|
||||
0,R_M8,REG8,_R,"\x1\x08",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x09",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x09",
|
||||
0,REG8,R_M8,_R,"\x1\x0A",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x0B",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x0B",
|
||||
0,R_M8,IMM8,_1|IB,"\x1\x80",
|
||||
0,R_M16,IMM16,O16|_1|IW,"\x1\x81",
|
||||
0,R_M32,IMM32,O32|_1|ID,"\x1\x81",
|
||||
0,R_M16,IMM8,O16|_1|IB,"\x1\x83",
|
||||
0,R_M32,IMM8,O32|_1|IB,"\x1\x83",
|
||||
"out",IMM8,AL,IB,"\x1\xE6",
|
||||
0,IMM8,AX,O16|IB,"\x1\xE7",
|
||||
0,IMM8,EAX,O32|IB,"\x1\xE7",
|
||||
"outsb",NONE,NONE,0,"\x1\x6E",
|
||||
"outsw",NONE,NONE,O16,"\x1\x6F",
|
||||
"outsd",NONE,NONE,O32,"\x1\x6F",
|
||||
"pop",REG16,NONE,O16|PLUSREG,"\x1\x58",
|
||||
0,REG32,NONE,O32|PLUSREG,"\x1\x58",
|
||||
0,R_M16,NONE,O16|_0,"\x1\x8F",
|
||||
0,R_M32,NONE,O32|_0,"\x1\x8F",
|
||||
"popa",NONE,NONE,0,"\x1\x61",
|
||||
"popaw",NONE,NONE,O16,"\x1\x61",
|
||||
"popad",NONE,NONE,O32,"\x1\x61",
|
||||
"popf",NONE,NONE,0,"\x1\x9D",
|
||||
"popfw",NONE,NONE,O16,"\x1\x9D",
|
||||
"popfd",NONE,NONE,O32,"\x1\x9D",
|
||||
"push",REG16,NONE,O16|PLUSREG,"\x1\x50",
|
||||
0,REG32,NONE,O32|PLUSREG,"\x1\x50",
|
||||
0,R_M16,NONE,O16|_6,"\x1\xFF",
|
||||
0,R_M32,NONE,O32|_6,"\x1\xFF",
|
||||
0,IMM8,NONE,IB,"\x1\x6A",
|
||||
0,IMM16,NONE,O16|IW,"\x1\x68",
|
||||
0,IMM32,NONE,O32|ID,"\x1\x68",
|
||||
"pusha",NONE,NONE,0,"\x1\x60",
|
||||
"pushad",NONE,NONE,O32,"\x1\x60",
|
||||
"pushaw",NONE,NONE,O16,"\x1\x60",
|
||||
"pushf",NONE,NONE,0,"\x1\x9C",
|
||||
"pushfd",NONE,NONE,O32,"\x1\x9C",
|
||||
"pushfw",NONE,NONE,O16,"\x1\x9C",
|
||||
"rcl",R_M8,CL,_2,"\x1\xD2",
|
||||
0,R_M8,IMM8,_2|IB,"\x1\xC0",
|
||||
0,R_M16,CL,O16|_2,"\x1\xD3",
|
||||
0,R_M16,IMM8,O16|_2|IB,"\x1\xC1",
|
||||
0,R_M32,CL,O32|_2,"\x1\xD3",
|
||||
0,R_M32,IMM8,O32|_2|IB,"\x1\xC1",
|
||||
"rcr",R_M8,CL,_3,"\x1\xD2",
|
||||
0,R_M8,IMM8,_3|IB,"\x1\xC0",
|
||||
0,R_M16,CL,O16|_3,"\x1\xD3",
|
||||
0,R_M16,IMM8,O16|_3|IB,"\x1\xC1",
|
||||
0,R_M32,CL,O32|_3,"\x1\xD3",
|
||||
0,R_M32,IMM8,O32|_3|IB,"\x1\xC1",
|
||||
"rdmsr",NONE,NONE,0,"\x2\x0F\x32",
|
||||
"rdpmc",NONE,NONE,0,"\x2\x0F\x33",
|
||||
"rdtsc",NONE,NONE,0,"\x2\x0F\x31",
|
||||
"ret",NONE,NONE,0,"\x1\xC3",
|
||||
0,IMM16,NONE,IW,"\x1\xC2",
|
||||
"retf",NONE,NONE,0,"\x1\xCB",
|
||||
0,IMM16,NONE,IW,"\x1\xCA",
|
||||
"retn",NONE,NONE,0,"\x1\xC3",
|
||||
0,IMM16,NONE,IW,"\x1\xC2",
|
||||
"rol",R_M8,CL,_0,"\x1\xD2",
|
||||
0,R_M8,IMM8,_0|IB,"\x1\xC0",
|
||||
0,R_M16,CL,O16|_0,"\x1\xD3",
|
||||
0,R_M16,IMM8,O16|_0|IB,"\x1\xC1",
|
||||
0,R_M32,CL,O32|_0,"\x1\xD3",
|
||||
0,R_M32,IMM8,O32|_0|IB,"\x1\xC1",
|
||||
"ror",R_M8,CL,_1,"\x1\xD2",
|
||||
0,R_M8,IMM8,_1|IB,"\x1\xC0",
|
||||
0,R_M16,CL,O16|_1,"\x1\xD3",
|
||||
0,R_M16,IMM8,O16|_1|IB,"\x1\xC1",
|
||||
0,R_M32,CL,O32|_1,"\x1\xD3",
|
||||
0,R_M32,IMM8,O32|_1|IB,"\x1\xC1",
|
||||
"rsm",NONE,NONE,0,"\x2\x0F\xAA",
|
||||
"sahf",NONE,NONE,0,"\x1\x9E",
|
||||
"sal",R_M8,CL,_4,"\x1\xD2",
|
||||
0,R_M8,IMM8,_4|IB,"\x1\xC0",
|
||||
0,R_M16,CL,O16|_4,"\x1\xD3",
|
||||
0,R_M16,IMM8,O16|_4|IB,"\x1\xC1",
|
||||
0,R_M32,CL,O32|_4,"\x1\xD3",
|
||||
0,R_M32,IMM8,O32|_4|IB,"\x1\xC1",
|
||||
"sar",R_M8,CL,_7,"\x1\xD2",
|
||||
0,R_M8,IMM8,_7|IB,"\x1\xC0",
|
||||
0,R_M16,CL,O16|_7,"\x1\xD3",
|
||||
0,R_M16,IMM8,O16|_7|IB,"\x1\xC1",
|
||||
0,R_M32,CL,O32|_7,"\x1\xD3",
|
||||
0,R_M32,IMM8,O32|_7|IB,"\x1\xC1",
|
||||
"salc",NONE,NONE,0,"\x1\xD6",
|
||||
"sbb",AL,IMM8,IB,"\x1\x1C",
|
||||
0,AX,IMM16,O16|IW,"\x1\x1D",
|
||||
0,EAX,IMM32,O32|ID,"\x1\x1D",
|
||||
0,R_M8,REG8,_R,"\x1\x18",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x19",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x19",
|
||||
0,REG8,R_M8,_R,"\x1\x1A",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x1B",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x1B",
|
||||
0,R_M8,IMM8,_3|IB,"\x1\x80",
|
||||
0,R_M16,IMM16,O16|_3|IW,"\x1\x81",
|
||||
0,R_M32,IMM32,O32|_3|ID,"\x1\x81",
|
||||
0,R_M16,IMM8,O16|_3|IB,"\x1\x83",
|
||||
0,R_M32,IMM8,O32|_3|IB,"\x1\x83",
|
||||
"scasb",NONE,NONE,0,"\x1\xAE",
|
||||
"scasw",NONE,NONE,O16,"\x1\xAF",
|
||||
"scasd",NONE,NONE,O32,"\x1\xAF",
|
||||
"sgdt",MEM,NONE,_0,"\x2\x0F\x01",
|
||||
"sidt",MEM,NONE,_1,"\x2\x0F\x01",
|
||||
"sldt",R_M16,NONE,_0,"\x2\x0F\x00",
|
||||
"shl",R_M8,CL,_4,"\x1\xD2",
|
||||
0,R_M8,IMM8,_4|IB,"\x1\xC0",
|
||||
0,R_M16,CL,O16|_4,"\x1\xD3",
|
||||
0,R_M16,IMM8,O16|_4|IB,"\x1\xC1",
|
||||
0,R_M32,CL,O32|_4,"\x1\xD3",
|
||||
0,R_M32,IMM8,O32|_4|IB,"\x1\xC1",
|
||||
"shr",R_M8,CL,_5,"\x1\xD2",
|
||||
0,R_M8,IMM8,_5|IB,"\x1\xC0",
|
||||
0,R_M16,CL,O16|_5,"\x1\xD3",
|
||||
0,R_M16,IMM8,O16|_5|IB,"\x1\xC1",
|
||||
0,R_M32,CL,O32|_5,"\x1\xD3",
|
||||
0,R_M32,IMM8,O32|_5|IB,"\x1\xC1",
|
||||
"smi",NONE,NONE,0,"\x1\xF1",
|
||||
"smsw",R_M16,NONE,_4,"\x2\x0F\x01",
|
||||
"stc",NONE,NONE,0,"\x1\xF9",
|
||||
"std",NONE,NONE,0,"\x1\xFD",
|
||||
"sti",NONE,NONE,0,"\x1\xFB",
|
||||
"stosb",NONE,NONE,0,"\x1\xAA",
|
||||
"stosw",NONE,NONE,O16,"\x1\xAB",
|
||||
"stosd",NONE,NONE,O32,"\x1\xAB",
|
||||
"str",R_M16,NONE,_1,"\x2\x0F\x00",
|
||||
"sub",AL,IMM8,IB,"\x1\x2C",
|
||||
0,AX,IMM16,O16|IW,"\x1\x2D",
|
||||
0,EAX,IMM32,O32|ID,"\x1\x2D",
|
||||
0,R_M8,REG8,_R,"\x1\x28",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x29",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x29",
|
||||
0,REG8,R_M8,_R,"\x1\x2A",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x2B",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x2B",
|
||||
0,R_M8,IMM8,_5|IB,"\x1\x80",
|
||||
0,R_M16,IMM16,O16|_5|IW,"\x1\x81",
|
||||
0,R_M32,IMM32,O32|_5|ID,"\x1\x81",
|
||||
0,R_M16,IMM8,O16|_5|IB,"\x1\x83",
|
||||
0,R_M32,IMM8,O32|_5|IB,"\x1\x83",
|
||||
"test",AL,IMM8,IB,"\x1\xA8",
|
||||
0,AX,IMM16,O16|IW,"\x1\xA9",
|
||||
0,EAX,IMM32,O32|ID,"\x1\xA9",
|
||||
0,R_M8,REG8,_R,"\x1\x84",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x85",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x85",
|
||||
0,R_M8,IMM8,_7|IB,"\x1\xF6",
|
||||
0,R_M16,IMM16,O16|_7|IW,"\x1\xF7",
|
||||
0,R_M32,IMM32,O32|_7|ID,"\x1\xF7",
|
||||
"umov",R_M8,REG8,_R,"\x2\x0F\x10",
|
||||
0,R_M16,REG16,O16|_R,"\x2\x0F\x11",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\x11",
|
||||
0,REG8,R_M8,_R,"\x2\x0F\x12",
|
||||
0,REG16,R_M16,O16|_R,"\x2\x0F\x13",
|
||||
0,REG32,R_M32,O32|_R,"\x2\x0F\x13",
|
||||
"verr",R_M16,NONE,_4,"\x2\x0F\x00",
|
||||
"verw",R_M16,NONE,_5,"\x2\x0F\x00",
|
||||
"wait",NONE,NONE,0,"\x1\x9B",
|
||||
"wbinvd",NONE,NONE,0,"\x2\x0F\x09",
|
||||
"wrmsr",NONE,NONE,0,"\x2\x0F\x30",
|
||||
"xadd",R_M8,REG8,_R,"\x2\x0F\xC0",
|
||||
0,R_M16,REG16,O16|_R,"\x2\x0F\xC1",
|
||||
0,R_M32,REG32,O32|_R,"\x2\x0F\xC1",
|
||||
"xbts",REG16,R_M16,O16|_R,"\x2\x0F\xA6",
|
||||
0,REG32,R_M32,O32|_R,"\x2\x0F\xA6",
|
||||
"xchg",REG8,R_M8,_R,"\x1\x86",
|
||||
0,REG16,R_M8,O16|_R,"\x1\x87",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x87",
|
||||
0,R_M8,REG8,_R,"\x1\x86",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x87",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x87",
|
||||
0,AX,REG16,O16|PLUSREG,"\x1\x90",
|
||||
0,EAX,REG32,O32|PLUSREG,"\x1\x90",
|
||||
0,REG16,AX,O16|PLUSREG,"\x1\x90",
|
||||
0,REG32,EAX,O32|PLUSREG,"\x1\x90",
|
||||
"xlatb",NONE,NONE,0,"\x1\xD7",
|
||||
"xor",AL,IMM8,IB,"\x1\x34",
|
||||
0,AX,IMM16,O16|IW,"\x1\x35",
|
||||
0,EAX,IMM32,O32|ID,"\x1\x35",
|
||||
0,R_M8,REG8,_R,"\x1\x30",
|
||||
0,R_M16,REG16,O16|_R,"\x1\x31",
|
||||
0,R_M32,REG32,O32|_R,"\x1\x31",
|
||||
0,REG8,R_M8,_R,"\x1\x32",
|
||||
0,REG16,R_M16,O16|_R,"\x1\x33",
|
||||
0,REG32,R_M32,O32|_R,"\x1\x33",
|
||||
0,R_M8,IMM8,_6|IB,"\x1\x80",
|
||||
0,R_M16,IMM16,O16|_6|IW,"\x1\x81",
|
||||
0,R_M32,IMM32,O32|_6|ID,"\x1\x81",
|
||||
0,R_M16,IMM8,O16|_6|IB,"\x1\x83",
|
||||
0,R_M32,IMM8,O32|_6|IB,"\x1\x83",
|
||||
"",0,0,0,0
|
||||
};
|
||||
@@ -0,0 +1,308 @@
|
||||
|
||||
/*
|
||||
|
||||
BlitzPC assembler.
|
||||
|
||||
This REALLY needs some work - very slow.
|
||||
|
||||
*/
|
||||
|
||||
#include "../std.h"
|
||||
#include "../ex.h"
|
||||
#include "assem_x86.h"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
typedef map<string,Inst*> InstMap;
|
||||
typedef InstMap::value_type InstPair;
|
||||
typedef InstMap::const_iterator InstIter;
|
||||
|
||||
static InstMap instMap;
|
||||
|
||||
//#define LOG
|
||||
|
||||
Assem_x86::Assem_x86( istream &in,Module *mod ):Assem(in,mod){
|
||||
|
||||
//build instruction map, if not built already.
|
||||
if( !instMap.size() ){
|
||||
for( int k=0;!insts[k].name || insts[k].name[0];++k ){
|
||||
if( insts[k].name ) instMap.insert( InstPair( insts[k].name,&insts[k] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int findCC( const string &s ){
|
||||
if( s=="o" ) return 0;
|
||||
if( s=="no" ) return 1;
|
||||
if( s=="b"||s=="c"||s=="nae" ) return 2;
|
||||
if( s=="ae"||s=="nb"||s=="nc" ) return 3;
|
||||
if( s=="e"||s=="z" ) return 4;
|
||||
if( s=="ne"||s=="nz" ) return 5;
|
||||
if( s=="be"||s=="na" ) return 6;
|
||||
if( s=="a"||s=="nbe" ) return 7;
|
||||
if( s=="s" ) return 8;
|
||||
if( s=="ns" ) return 9;
|
||||
if( s=="p"||s=="pe" ) return 10;
|
||||
if( s=="ne"||s=="po" ) return 11;
|
||||
if( s=="l"||s=="nge" ) return 12;
|
||||
if( s=="ge"||s=="nl" ) return 13;
|
||||
if( s=="le"||s=="ng" ) return 14;
|
||||
if( s=="g"||s=="nle" ) return 15;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Assem_x86::align( int n ){
|
||||
int pc=mod->getPC();
|
||||
int sz=(pc+(n-1))/n*n-pc;
|
||||
while( sz-- ) mod->emit( 0x90 );
|
||||
}
|
||||
|
||||
void Assem_x86::emit( int n ){
|
||||
#ifdef LOG
|
||||
clog<<hex<<(int(n)&0xff)<<dec<<' ';
|
||||
#endif
|
||||
mod->emit( n );
|
||||
}
|
||||
|
||||
void Assem_x86::emitw( int n ){
|
||||
emit( n );
|
||||
emit( (n>>8) );
|
||||
}
|
||||
|
||||
void Assem_x86::emitd( int n ){
|
||||
emitw( n );
|
||||
emitw( n>>16 );
|
||||
}
|
||||
|
||||
void Assem_x86::emitImm( const Operand &o,int size ){
|
||||
|
||||
if( size<4 && o.immLabel.size() ) throw Ex( "immediate value cannot by a label" );
|
||||
|
||||
switch( size ){
|
||||
case 1:emit( o.imm );return;
|
||||
case 2:emitw( o.imm );return;
|
||||
case 4:a_reloc( o.immLabel );emitd( o.imm );return;
|
||||
}
|
||||
}
|
||||
|
||||
void Assem_x86::emitImm( const string &s,int size ){
|
||||
|
||||
Operand op(s);op.parse();
|
||||
if( !(op.mode&IMM) ) throw Ex( "operand must be immediate" );
|
||||
emitImm( op,size );
|
||||
}
|
||||
|
||||
void Assem_x86::r_reloc( const string &s ){
|
||||
if( !s.size() ) return;
|
||||
mod->addReloc( s.c_str(),mod->getPC(),true );
|
||||
}
|
||||
|
||||
void Assem_x86::a_reloc( const string &s ){
|
||||
if( !s.size() ) return;
|
||||
mod->addReloc( s.c_str(),mod->getPC(),false );
|
||||
}
|
||||
|
||||
void Assem_x86::assemInst( const string &name,const string &lhs,const string &rhs ){
|
||||
|
||||
//parse operands
|
||||
Operand lop( lhs ),rop( rhs );
|
||||
lop.parse();rop.parse();
|
||||
|
||||
//find instruction
|
||||
int cc=-1;
|
||||
Inst *inst=0;
|
||||
|
||||
//kludge for condition code instructions...
|
||||
if( name[0]=='j' ){
|
||||
if( (cc=findCC(name.substr(1)))>=0 ){
|
||||
static Inst jCC={ "jCC",IMM,NONE,RW_RD|PLUSCC,"\x2\x0F\x80" };
|
||||
inst=&jCC;
|
||||
}
|
||||
}else if( name[0]=='s' && name.substr( 0,3 )=="set" ){
|
||||
if( (cc=findCC(name.substr(3)))>=0 ){
|
||||
static Inst setCC={ "setne",R_M8,NONE,_2|PLUSCC,"\x2\x0F\x90" };
|
||||
inst=&setCC;
|
||||
}
|
||||
}
|
||||
|
||||
if( inst ){
|
||||
if( !(lop.mode&inst->lmode) || !(rop.mode&inst->rmode) ) throw Ex( "illegal addressing mode" );
|
||||
}else{
|
||||
InstIter it=instMap.find( name );
|
||||
if( it==instMap.end() ) throw Ex( "unrecognized instruction" );
|
||||
inst=it->second;
|
||||
for(;;){
|
||||
if( (lop.mode&inst->lmode) && (rop.mode&inst->rmode) ) break;
|
||||
if( (++inst)->name ) throw Ex( "illegal addressing mode" );
|
||||
}
|
||||
}
|
||||
|
||||
//16/32 bit modifier - NOP for now
|
||||
if( inst->flags & (O16|O32) ){}
|
||||
|
||||
int k,n=inst->bytes[0];
|
||||
for( k=1;k<n;++k ) emit( inst->bytes[k] );
|
||||
if( inst->flags&PLUSREG ) emit( inst->bytes[k]+lop.reg );
|
||||
else if( inst->flags&PLUSCC ) emit( inst->bytes[k]+cc );
|
||||
else emit( inst->bytes[k] );
|
||||
|
||||
if( inst->flags&(_0|_1|_2|_3|_4|_5|_6|_7|_R ) ){
|
||||
|
||||
//find the memop;
|
||||
const Operand &mop=
|
||||
(inst->rmode&(MEM|MEM8|MEM16|MEM32|R_M|R_M8|R_M16|R_M32))?rop:lop;
|
||||
|
||||
//find the spare field value.
|
||||
int rm=0;
|
||||
switch( inst->flags&(_0|_1|_2|_3|_4|_5|_6|_7|_R ) ){
|
||||
case _0:rm=0;break;case _1:rm=1;break;case _2:rm=2;break;case _3:rm=3;break;
|
||||
case _4:rm=4;break;case _5:rm=5;break;case _6:rm=6;break;case _7:rm=7;break;
|
||||
case _R:rm=(inst->rmode&(REG8|REG16|REG32))?rop.reg:lop.reg;break;
|
||||
}
|
||||
rm<<=3;
|
||||
if( mop.mode & REG ){ //reg
|
||||
emit( 0xc0|rm|mop.reg );
|
||||
}else if( mop.baseReg>=0 ){ //base, index?
|
||||
int mod=mop.offset ? 0x40 : 0x00;
|
||||
if( mop.baseLabel.size() || mop.offset<-128 || mop.offset>127 ) mod=0x80;
|
||||
if( mop.baseReg==5 && !mod ) mod=0x40;
|
||||
if( mop.indexReg>=0 ){ //base, index!
|
||||
emit( mod|rm|4 );
|
||||
emit( (mop.shift<<6)|(mop.indexReg<<3)|mop.baseReg );
|
||||
}else{ //base, no index!
|
||||
if( mop.baseReg!=4 ) emit( mod|rm|mop.baseReg);
|
||||
else{
|
||||
emit( mod|rm|4 );emit( (4<<3)|mop.baseReg );
|
||||
}
|
||||
}
|
||||
if( (mod&0xc0)==0x40 ) emit( mop.offset );
|
||||
else if( (mod&0xc0)==0x80 ){
|
||||
//reloc
|
||||
a_reloc( mop.baseLabel );emitd( mop.offset );
|
||||
}
|
||||
}else if( mop.indexReg>=0 ){ //index, no base!
|
||||
emit( rm|4 );
|
||||
emit( (mop.shift<<6)|(mop.indexReg<<3)|5 );
|
||||
//reloc
|
||||
a_reloc( mop.baseLabel );emitd( mop.offset );
|
||||
}else{ //[disp]
|
||||
emit( rm|5 );
|
||||
//reloc
|
||||
a_reloc( mop.baseLabel );emitd( mop.offset );
|
||||
}
|
||||
}
|
||||
|
||||
if( inst->flags&RW_RD ){
|
||||
r_reloc( lop.immLabel );emitd( lop.imm-4 );
|
||||
}
|
||||
|
||||
if( inst->flags&IB ){
|
||||
if( lop.mode&IMM ) emitImm( lop,1 );else emitImm( rop,1 );
|
||||
}else if( inst->flags&IW ){
|
||||
if( lop.mode&IMM ) emitImm( lop,2 );else emitImm( rop,2 );
|
||||
}else if( inst->flags&ID ){
|
||||
if( lop.mode&IMM ) emitImm( lop,4 );else emitImm( rop,4 );
|
||||
}
|
||||
}
|
||||
|
||||
void Assem_x86::assemDir( const string &name,const string &op ){
|
||||
|
||||
if( !op.size() ) throw Ex( "operand error" );
|
||||
|
||||
if( name==".db" ){
|
||||
if( op[0]!='\"' ) emitImm( op,1 );
|
||||
else{
|
||||
if( op.size()<2 || op[op.size()-1]!='\"' ) throw Ex( "operand error" );
|
||||
for( int k=1;k<op.size()-1;++k ) emit( op[k] );
|
||||
}
|
||||
}else if( name==".dw" ){
|
||||
emitImm( op,2 );
|
||||
}else if( name==".dd" ){
|
||||
emitImm( op,4 );
|
||||
}else if( name==".align" ){
|
||||
Operand o( op );o.parse();
|
||||
if( !(o.mode&IMM) ) throw Ex( "operand must be immediate" );
|
||||
align( o.imm );
|
||||
}else{
|
||||
throw Ex( "unrecognized assembler directive" );
|
||||
}
|
||||
}
|
||||
|
||||
void Assem_x86::assemLine( const string &line ){
|
||||
|
||||
int i=0;
|
||||
string name;
|
||||
vector<string> ops;
|
||||
|
||||
//label?
|
||||
if( !isspace( line[i] ) ){
|
||||
while( !isspace( line[i] ) ) ++i;
|
||||
string lab=line.substr( 0,i );
|
||||
if( !mod->addSymbol( lab.c_str(),mod->getPC() ) ) throw Ex( "duplicate label" );
|
||||
}
|
||||
|
||||
//skip space
|
||||
while( isspace( line[i] ) && line[i]!='\n' ) ++i;
|
||||
if( line[i]=='\n' || line[i]==';' ) return;
|
||||
|
||||
//fetch instruction name
|
||||
int from=i;for( ++i;!isspace( line[i] );++i ){}
|
||||
name=line.substr( from,i-from );
|
||||
|
||||
for(;;){
|
||||
|
||||
//skip space
|
||||
while( isspace( line[i] ) && line[i]!='\n' ) ++i;
|
||||
if( line[i]=='\n' || line[i]==';' ) break;
|
||||
|
||||
int from=i;
|
||||
if( line[i]=='\"' ){
|
||||
for( ++i;line[i]!='\"' && line[i]!='\n';++i ){}
|
||||
if( line[i++]!='\"' ) throw Ex( "missing close quote" );
|
||||
}else{
|
||||
for( ++i;line[i]!=',' && line[i]!=';' && line[i]!='\n';++i ){}
|
||||
}
|
||||
|
||||
//back-up over space
|
||||
while( i && isspace( line[i-1] ) ) --i;
|
||||
ops.push_back( line.substr( from,i-from ) );
|
||||
|
||||
//skip space
|
||||
while( isspace( line[i] ) && line[i]!='\n' ) ++i;
|
||||
if( line[i]=='\n' || line[i]==';' ) break;
|
||||
|
||||
if( line[i++]!=',' ) throw Ex( "expecting ','" );
|
||||
}
|
||||
|
||||
//pseudo op?
|
||||
if( name[0]=='.' ){
|
||||
for( int k=0;k<ops.size();++k ) assemDir( name,ops[k] );
|
||||
return;
|
||||
}
|
||||
|
||||
//normal instruction!
|
||||
if( ops.size()>2 ) throw Ex( "Too many operands" );
|
||||
ops.push_back( "" );ops.push_back( "" );
|
||||
assemInst( name,ops[0],ops[1] );
|
||||
}
|
||||
|
||||
void Assem_x86::assemble(){
|
||||
|
||||
string line;
|
||||
|
||||
while( !in.eof() ){
|
||||
try{
|
||||
getline( in,line );
|
||||
line+='\n';
|
||||
#ifdef LOG
|
||||
clog<<line;
|
||||
#endif
|
||||
assemLine( line );
|
||||
#ifdef LOG
|
||||
clog<<endl;
|
||||
#endif
|
||||
}catch( Ex &x ){
|
||||
throw Ex( line+x.ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
#ifndef ASSEM_X86_H
|
||||
#define ASSEM_X86_H
|
||||
|
||||
#include "../assem.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include "insts.h"
|
||||
#include "operand.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Assem_x86 : public Assem{
|
||||
public:
|
||||
Assem_x86( istream &in,Module *mod );
|
||||
|
||||
virtual void assemble();
|
||||
|
||||
private:
|
||||
|
||||
void align( int n );
|
||||
void emit( int n );
|
||||
void emitw( int n );
|
||||
void emitd( int n );
|
||||
void emitImm( const string &s,int size );
|
||||
void emitImm( const Operand &o,int size );
|
||||
void r_reloc( const string &dest );
|
||||
void a_reloc( const string &dest );
|
||||
void assemDir( const string &name,const string &op );
|
||||
void assemInst( const string &name,const string &lhs,const string &rhs );
|
||||
void assemLine( const string &line );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
#ifndef INSTS_H
|
||||
#define INSTS_H
|
||||
|
||||
//operand addressing modes
|
||||
enum{
|
||||
REG=0x0001,REG8=0x0002,REG16=0x0004,REG32=0x0008,
|
||||
IMM=0x0010,IMM8=0x0020,IMM16=0x0040,IMM32=0x0080,
|
||||
MEM=0x0100,MEM8=0x0200,MEM16=0x0400,MEM32=0x0800,
|
||||
R_M=0x1000,R_M8=0x2000,R_M16=0x4000,R_M32=0x8000,
|
||||
|
||||
AL=0x10000,AX=0x20000,EAX=0x40000,
|
||||
CL=0x80000,CX=0x100000,ECX=0x200000,
|
||||
ST0=0x400000,FPUREG=0x800000,
|
||||
|
||||
NONE=0x80000000
|
||||
};
|
||||
|
||||
//flags
|
||||
enum{
|
||||
O16=0x001,O32=0x0002,OW_OD=0x0004,
|
||||
PLUSREG=0x0008,PLUSCC=0x0010,
|
||||
_0=0x0020,_1=0x0040,_2=0x0080,_3=0x0100,
|
||||
_4=0x0200,_5=0x0400,_6=0x0800,_7=0x1000,_R=0x2000,
|
||||
IB=0x4000,IW=0x8000,ID=0x10000,RW_RD=0x20000
|
||||
};
|
||||
|
||||
//an instruction
|
||||
struct Inst{
|
||||
const char *name; //0, then same as last.
|
||||
int lmode,rmode,flags; //left mode,right mode,flags
|
||||
const char *bytes; //the bytes.
|
||||
};
|
||||
|
||||
extern Inst insts[];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,160 @@
|
||||
|
||||
#include "../std.h"
|
||||
#include "../ex.h"
|
||||
#include "operand.h"
|
||||
#include "insts.h"
|
||||
|
||||
static const char *regs[]={
|
||||
"al","cl","dl","bl","ah","ch","dh","bh",
|
||||
"ax","cx","dx","bx","sp","bp","si","di",
|
||||
"eax","ecx","edx","ebx","esp","ebp","esi","edi"
|
||||
};
|
||||
|
||||
static void opError(){
|
||||
throw Ex( "error in operand" );
|
||||
}
|
||||
|
||||
static void sizeError(){
|
||||
throw Ex( "illegal operand size" );
|
||||
}
|
||||
|
||||
Operand::Operand()
|
||||
:mode(NONE),reg(-1),imm(0),offset(0),baseReg(-1),indexReg(-1),shift(0){
|
||||
}
|
||||
|
||||
Operand::Operand( const string &s )
|
||||
:mode(NONE),reg(-1),imm(0),offset(0),baseReg(-1),indexReg(-1),shift(0),s(s){
|
||||
}
|
||||
|
||||
bool Operand::parseSize( int *sz ){
|
||||
|
||||
if( !s.size() ) return false;
|
||||
if( s.find( "byte " )==0 ){
|
||||
*sz=1;s=s.substr( 5 );
|
||||
}else if( s.find( "word " )==0 ){
|
||||
*sz=2;s=s.substr( 5 );
|
||||
}else if( s.find( "dword " )==0 ){
|
||||
*sz=4;s=s.substr( 6 );
|
||||
}else return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Operand::parseChar( char c ){
|
||||
if( !s.size() || s[0]!=c ) return false;
|
||||
s=s.substr( 1 );return true;
|
||||
}
|
||||
|
||||
bool Operand::parseReg( int *reg ){
|
||||
int i;
|
||||
for( i=0;i<s.size() && isalpha( s[i] );++i ){}
|
||||
if( !i ) return false;
|
||||
string t=s.substr(0,i);
|
||||
for( int j=0;j<24;++j ){
|
||||
if( t==regs[j] ){ *reg=j;s=s.substr( i );return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Operand::parseFPReg( int *reg ){
|
||||
|
||||
//eg: st(0)
|
||||
if( s.size()<5 ) return false;
|
||||
if( s[0]!='s' || s[1]!='t' || s[2]!='(' || s[4]!=')' ) return false;
|
||||
if( s[3]<'0' || s[3]>'7' ) return false;
|
||||
*reg=s[3]-'0';s=s.substr( 5 );return true;
|
||||
}
|
||||
|
||||
bool Operand::parseLabel( string *label ){
|
||||
if( !s.size() || (!isalpha( s[0] ) && s[0]!='_') ) return false;
|
||||
int i;
|
||||
for( i=1;i<s.size() && (isalnum( s[i] ) || s[i]=='_');++i ){}
|
||||
*label=s.substr(0,i);s=s.substr( i );return true;
|
||||
}
|
||||
|
||||
bool Operand::parseConst( int *iconst ){
|
||||
int i,sgn=s.size() && (s[0]=='-'||s[0]=='+');
|
||||
for( i=sgn;i<s.size() && isdigit( s[i] );++i ){}
|
||||
if( i==sgn ) return false;
|
||||
int n=atoi( s.c_str() );
|
||||
*iconst=n;s=s.substr( i );return true;
|
||||
}
|
||||
|
||||
void Operand::parse(){
|
||||
|
||||
if( !s.size() ) return;
|
||||
|
||||
int sz;if( !parseSize( &sz ) ) sz=0;
|
||||
|
||||
if( s[0]!='[' ){
|
||||
int r;
|
||||
if( parseReg( &r ) ){
|
||||
mode=REG|R_M;
|
||||
if( r<8 ){
|
||||
if( sz && sz!=1 ) sizeError();
|
||||
mode|=REG8|R_M8;
|
||||
if( r==0 ) mode|=AL;else if( r==1 ) mode|=CL;
|
||||
}else if( r<16 ){
|
||||
if( sz && sz!=2 ) sizeError();
|
||||
mode|=REG16|R_M16;
|
||||
if( r==8 ) mode|=AX;else if( r==9 ) mode|=CX;
|
||||
}else{
|
||||
if( sz && sz!=4 ) sizeError();
|
||||
mode|=REG32|R_M32;
|
||||
if( r==16 ) mode|=EAX;else if( r==17 ) mode|=ECX;
|
||||
}
|
||||
reg=r&7;
|
||||
}else if( parseFPReg( &r ) ){
|
||||
mode=FPUREG;
|
||||
if( !r ) mode|=ST0;
|
||||
reg=r;
|
||||
}else if( parseLabel( &immLabel ) ){
|
||||
if( sz && sz!=4 ) sizeError();
|
||||
mode=IMM|IMM32;
|
||||
}else if( parseConst( &imm ) ){
|
||||
mode=IMM;
|
||||
if( sz==1 ) mode|=IMM8;
|
||||
else if( sz==2 ) mode|=IMM16;
|
||||
else mode|=IMM32;
|
||||
}else opError();
|
||||
if( s.size() ) opError();
|
||||
return;
|
||||
}
|
||||
|
||||
if( s[s.size()-1]!=']' ) opError();
|
||||
s=s.substr( 1,s.size()-2 );
|
||||
|
||||
mode=MEM|R_M;
|
||||
if( sz==1 ) mode|=MEM8|R_M8;
|
||||
else if( sz==2 ) mode|=MEM16|R_M16;
|
||||
else mode|=MEM32|R_M32;
|
||||
|
||||
for(;;){
|
||||
int n;string l;
|
||||
if( parseReg( &n ) ){
|
||||
if( n<16 ) throw Ex( "register must be 32 bit" );
|
||||
n&=7;
|
||||
if( parseChar( '*' ) ){
|
||||
if( n==4 ) break; //esp cannot be index reg!
|
||||
if( indexReg>=0 ) break;
|
||||
if( parseChar( '1' ) ) shift=0;
|
||||
else if( parseChar( '2' ) ) shift=1;
|
||||
else if( parseChar( '4' ) ) shift=2;
|
||||
else if( parseChar( '8' ) ) shift=3;
|
||||
else break;
|
||||
indexReg=n;
|
||||
}else{
|
||||
if( baseReg<0 ) baseReg=n;
|
||||
else if( indexReg<0 ){ indexReg=n; }
|
||||
else break;
|
||||
}
|
||||
}else if( parseLabel( &l ) ){
|
||||
if( baseLabel.size() ) opError();
|
||||
baseLabel=l;
|
||||
}else if( parseConst( &n ) ){
|
||||
offset+=n;
|
||||
}else break;
|
||||
if( !s.size() ) return;
|
||||
}
|
||||
opError();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
#ifndef OPERAND_H
|
||||
#define OPERAND_H
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Operand{
|
||||
|
||||
int mode;
|
||||
int reg,imm,offset;
|
||||
string immLabel,baseLabel;
|
||||
int baseReg,indexReg,shift;
|
||||
|
||||
Operand();
|
||||
Operand( const string &s );
|
||||
|
||||
void parse();
|
||||
|
||||
private:
|
||||
string s;
|
||||
bool parseSize( int *sz );
|
||||
bool parseChar( char c );
|
||||
bool parseReg( int *reg );
|
||||
bool parseFPReg( int *reg );
|
||||
bool parseLabel( string *t );
|
||||
bool parseConst( int *iconst );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
Blitz Basic internals.
|
||||
|
||||
* Language
|
||||
|
||||
Declarations:
|
||||
|
||||
4 types: Newtype, Function, Var, Array
|
||||
|
||||
Forward referencing for NewTypes and Functions is allowed.
|
||||
|
||||
Array declarations are through Dim statement.
|
||||
|
||||
Var declarations are through Var statement or params.
|
||||
|
||||
Only Var declarations may appear in functions.
|
||||
|
||||
|
||||
* Runtime
|
||||
|
||||
Newtype objects in BB look like this:
|
||||
|
||||
struct BBObj{
|
||||
BBObj *curr;
|
||||
int ref_cnt;
|
||||
BBObj *next,BBObj *prev;
|
||||
};
|
||||
|
||||
When an object is 'used' (for field access or in an expression), it's
|
||||
curr field should be fetched.
|
||||
|
||||
When an object is assigned, prev obj refcnt is decremented, new refcnt
|
||||
is incremented.
|
||||
|
||||
The curr field is 0 if the object has been deleted.
|
||||
|
||||
All objects exist in a type list:
|
||||
|
||||
struct BBType{
|
||||
int obj_size
|
||||
BBObj usedList,freeList;
|
||||
};
|
||||
|
||||
An object stays in it's type list as long as it's ref_cnt is >0.
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
/*
|
||||
|
||||
A block represents a function - code & data.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BLOCK_H
|
||||
#define BLOCK_H
|
||||
|
||||
struct Block{
|
||||
|
||||
Block( Block *parent );
|
||||
~Block();
|
||||
|
||||
void genCode( TNode *t ){ code.push_back( t ); }
|
||||
void genData( TNode *t ){ data.push_back( t ); }
|
||||
|
||||
void generate( Codegen *gen );
|
||||
|
||||
private:
|
||||
Block *parent;
|
||||
vector<Block*> children;
|
||||
|
||||
vector<TNode*> code;
|
||||
vector<TNode*> data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
#ifndef CODEGEN_H
|
||||
#define CODEGEN_H
|
||||
|
||||
#include "std.h"
|
||||
|
||||
enum{
|
||||
IR_JUMP,IR_JUMPT,IR_JUMPF,IR_JUMPGE,
|
||||
|
||||
IR_SEQ,IR_MOVE,IR_MEM,IR_LOCAL,IR_GLOBAL,IR_ARG,IR_CONST,
|
||||
|
||||
IR_JSR,IR_RET,IR_AND,IR_OR,IR_XOR,IR_SHL,IR_SHR,IR_SAR,
|
||||
|
||||
IR_CALL,IR_RETURN,IR_CAST,
|
||||
IR_NEG,IR_ADD,IR_SUB,IR_MUL,IR_DIV,
|
||||
IR_SETEQ,IR_SETNE,IR_SETLT,IR_SETGT,IR_SETLE,IR_SETGE,
|
||||
|
||||
IR_FCALL,IR_FRETURN,IR_FCAST,
|
||||
IR_FNEG,IR_FADD,IR_FSUB,IR_FMUL,IR_FDIV,
|
||||
IR_FSETEQ,IR_FSETNE,IR_FSETLT,IR_FSETGT,IR_FSETLE,IR_FSETGE,
|
||||
};
|
||||
|
||||
struct TNode{
|
||||
|
||||
int op; //opcode
|
||||
TNode *l,*r; //args
|
||||
int iconst; //for CONST type_int
|
||||
string sconst; //for CONST type_string
|
||||
|
||||
TNode( int op,TNode *l=0,TNode *r=0 ):op(op),l(l),r(r),iconst(0){}
|
||||
TNode( int op,TNode *l,TNode *r,int i ):op(op),l(l),r(r),iconst(i){}
|
||||
TNode( int op,TNode *l,TNode *r,const string &s ):op(op),l(l),r(r),iconst(0),sconst(s){}
|
||||
~TNode(){ delete l;delete r; }
|
||||
|
||||
void log();
|
||||
};
|
||||
|
||||
class Codegen{
|
||||
public:
|
||||
ostream &out;
|
||||
bool debug;
|
||||
Codegen( ostream &out,bool debug ):out( out ),debug( debug ){}
|
||||
|
||||
virtual void enter( const string &l,int frameSize )=0;
|
||||
virtual void code( TNode *code )=0;
|
||||
virtual void leave( TNode *cleanup,int pop_sz )=0;
|
||||
virtual void label( const string &l )=0;
|
||||
virtual void i_data( int i,const string &l="" )=0;
|
||||
virtual void s_data( const string &s,const string &l="" )=0;
|
||||
virtual void p_data( const string &p,const string &l="" )=0;
|
||||
virtual void align_data( int n )=0;
|
||||
virtual void flush()=0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,456 @@
|
||||
|
||||
#include "../std.h"
|
||||
#include "codegen_x86.h"
|
||||
#include "tile.h"
|
||||
|
||||
//#define NOOPTS
|
||||
|
||||
Codegen_x86::Codegen_x86( ostream &out,bool debug ):Codegen( out,debug ),inCode(false){
|
||||
}
|
||||
|
||||
static string itoa_sgn(int n){
|
||||
return n ? (n>0 ? "+"+itoa(n) : itoa(n)) : "";
|
||||
}
|
||||
|
||||
static bool isRelop( int op ){
|
||||
return op==IR_SETEQ||op==IR_SETNE||op==IR_SETLT||op==IR_SETGT||op==IR_SETLE||op==IR_SETGE;
|
||||
}
|
||||
|
||||
static bool nodesEqual( TNode *t1,TNode *t2 ){
|
||||
if( t1->op!=t2->op ||
|
||||
t1->iconst!=t2->iconst ||
|
||||
t1->sconst!=t2->sconst ) return false;
|
||||
|
||||
if( t1->l ){
|
||||
if( !t2->l || !nodesEqual( t1->l,t2->l ) ) return false;
|
||||
}else if( t2->l ) return false;
|
||||
|
||||
if( t1->r ){
|
||||
if( !t2->r || !nodesEqual( t1->r,t2->r ) ) return false;
|
||||
}else if( t2->r ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool getShift( int n,int &shift ){
|
||||
#ifdef NOOPTS
|
||||
return false;
|
||||
#endif
|
||||
|
||||
for( shift=0;shift<32;++shift ){
|
||||
if( (1<<shift)==n ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool matchMEM( TNode *t,string &s ){
|
||||
#ifdef NOOPTS
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if( t->op!=IR_MEM ) return false;
|
||||
t=t->l;
|
||||
switch( t->op ){
|
||||
case IR_GLOBAL:s="["+t->sconst+"]";return true;
|
||||
case IR_LOCAL:s="[ebp"+itoa_sgn(t->iconst)+"]";return true;
|
||||
case IR_ARG:s="[esp"+itoa_sgn(t->iconst)+"]";return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool matchCONST( TNode *t,string &s ){
|
||||
#ifdef NOOPTS
|
||||
return false;
|
||||
#endif
|
||||
|
||||
switch( t->op ){
|
||||
case IR_CONST:s=itoa( t->iconst );return true;
|
||||
case IR_GLOBAL:s=t->sconst;return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool matchMEMCONST( TNode *t,string &s ){
|
||||
#ifdef NOOPTS
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return matchMEM( t,s ) || matchCONST( t,s );
|
||||
}
|
||||
|
||||
Tile *Codegen_x86::genCompare( TNode *t,string &func,bool negate ){
|
||||
|
||||
switch( t->op ){
|
||||
case IR_SETEQ:func=negate ? "nz" : "z";break;
|
||||
case IR_SETNE:func=negate ? "z" : "nz";break;
|
||||
case IR_SETLT:func=negate ? "ge" : "l";break;
|
||||
case IR_SETGT:func=negate ? "le" : "g";break;
|
||||
case IR_SETLE:func=negate ? "g" : "le";break;
|
||||
case IR_SETGE:func=negate ? "l" : "ge";break;
|
||||
default:return 0;
|
||||
}
|
||||
|
||||
string q,m,c;
|
||||
TNode *ql=0,*qr=0;
|
||||
|
||||
if( matchMEM( t->l,m ) ){
|
||||
if( matchCONST( t->r,c ) ){
|
||||
q="\tcmp\t"+m+","+c+"\n";
|
||||
}else{
|
||||
q="\tcmp\t"+m+",%l\n";ql=t->r;
|
||||
}
|
||||
}else{
|
||||
if( matchMEMCONST( t->r,m ) ){
|
||||
q="\tcmp\t%l,"+m+"\n";ql=t->l;
|
||||
}else{
|
||||
q="\tcmp\t%l,%r\n";ql=t->l;qr=t->r;
|
||||
}
|
||||
}
|
||||
|
||||
return d_new Tile( q,ql ? munchReg( ql ) : 0,qr ? munchReg( qr ) : 0 );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Integer expressions returned in a register //
|
||||
////////////////////////////////////////////////
|
||||
Tile *Codegen_x86::munchUnary( TNode *t ){
|
||||
string s;
|
||||
switch( t->op ){
|
||||
case IR_NEG:s="\tneg\t%l\n";break;
|
||||
default:return 0;
|
||||
}
|
||||
return d_new Tile( s,munchReg( t->l ) );
|
||||
}
|
||||
|
||||
Tile *Codegen_x86::munchLogical( TNode *t ){
|
||||
string s;
|
||||
switch( t->op ){
|
||||
case IR_AND:s="\tand\t%l,%r\n";break;
|
||||
case IR_OR:s="\tor\t%l,%r\n";break;
|
||||
case IR_XOR:s="\txor\t%l,%r\n";break;
|
||||
default:return 0;
|
||||
}
|
||||
return d_new Tile( s,munchReg( t->l ),munchReg( t->r ) );
|
||||
}
|
||||
|
||||
Tile *Codegen_x86::munchArith( TNode *t ){
|
||||
|
||||
if( t->op==IR_DIV ){
|
||||
int shift;
|
||||
if( t->r->op==IR_CONST ){
|
||||
if( getShift( t->r->iconst,shift ) ){
|
||||
return d_new Tile( "\tsar\t%l,byte "+itoa(shift)+"\n",munchReg( t->l ) );
|
||||
}
|
||||
}
|
||||
Tile *q=d_new Tile( "\tcdq\n\tidiv\tecx\n",munchReg( t->l ),munchReg( t->r ) );
|
||||
q->want_l=EAX;q->want_r=ECX;q->hits=1<<EDX;
|
||||
return q;
|
||||
}
|
||||
|
||||
if( t->op==IR_MUL ){
|
||||
int shift;
|
||||
if( t->r->op==IR_CONST ){
|
||||
if( getShift( t->r->iconst,shift ) ){
|
||||
return d_new Tile( "\tshl\t%l,byte "+itoa(shift)+"\n",munchReg( t->l ) );
|
||||
}
|
||||
}else if( t->l->op==IR_CONST ){
|
||||
if( getShift( t->l->iconst,shift ) ){
|
||||
return d_new Tile( "\tshl\t%l,byte "+itoa(shift)+"\n",munchReg( t->r ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string s,op;
|
||||
switch( t->op ){
|
||||
case IR_ADD:op="\tadd\t";break;
|
||||
case IR_SUB:op="\tsub\t";break;
|
||||
case IR_MUL:op="\timul\t";break;
|
||||
default:return 0;
|
||||
}
|
||||
|
||||
if( matchMEMCONST( t->r,s ) ){
|
||||
return d_new Tile( op+"%l,"+s+"\n",munchReg( t->l ) );
|
||||
}
|
||||
if( t->op!=IR_SUB && matchMEMCONST( t->l,s ) ){
|
||||
return d_new Tile( op+"%l,"+s+"\n",munchReg( t->r ) );
|
||||
}
|
||||
return d_new Tile( op+"%l,%r\n",munchReg( t->l ),munchReg( t->r ) );
|
||||
}
|
||||
|
||||
Tile *Codegen_x86::munchShift( TNode *t ){
|
||||
string s,op;
|
||||
switch( t->op ){
|
||||
case IR_SHL:op="\tshl\t";break;
|
||||
case IR_SHR:op="\tshr\t";break;
|
||||
case IR_SAR:op="\tsar\t";break;
|
||||
default:return 0;
|
||||
}
|
||||
|
||||
if( matchCONST( t->r,s ) ){
|
||||
return d_new Tile( op+"%l,byte "+s+"\n",munchReg( t->l ) );
|
||||
}
|
||||
|
||||
Tile *q=d_new Tile( op+"%l,cl\n",munchReg( t->l ),munchReg( t->r ) );
|
||||
q->want_r=ECX;return q;
|
||||
}
|
||||
|
||||
Tile *Codegen_x86::munchRelop( TNode *t ){
|
||||
string func;
|
||||
Tile *q=genCompare( t,func,false );
|
||||
|
||||
q=d_new Tile( "\tset"+func+"\tal\n\tmovzx\teax,al\n",q );
|
||||
q->want_l=EAX;
|
||||
return q;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Float expressions returned on the FP stack //
|
||||
////////////////////////////////////////////////
|
||||
Tile *Codegen_x86::munchFPUnary( TNode *t ){
|
||||
string s;
|
||||
switch( t->op ){
|
||||
case IR_FNEG:s="\tfchs\n";break;
|
||||
default:return 0;
|
||||
}
|
||||
return d_new Tile( s,munchFP( t->l ) );
|
||||
}
|
||||
|
||||
Tile *Codegen_x86::munchFPArith( TNode *t ){
|
||||
string s,s2;
|
||||
switch( t->op ){
|
||||
case IR_FADD:s="\tfaddp\tst(1)\n";break;
|
||||
case IR_FMUL:s="\tfmulp\tst(1)\n";break;
|
||||
case IR_FSUB:s="\tfsubrp\tst(1)\n";s2="\tfsubp\tst(1)\n";break;
|
||||
case IR_FDIV:s="\tfdivrp\tst(1)\n";s2="\tfdivp\tst(1)\n";break;
|
||||
default:return 0;
|
||||
}
|
||||
return d_new Tile( s,s2,munchFP( t->l ),munchFP( t->r ) );
|
||||
}
|
||||
|
||||
Tile *Codegen_x86::munchFPRelop( TNode *t ){
|
||||
string s,s2;
|
||||
switch( t->op ){
|
||||
case IR_FSETEQ:s="z";s2="z";break;
|
||||
case IR_FSETNE:s="nz";s2="nz";break;
|
||||
case IR_FSETLT:s="b";s2="a";break;
|
||||
case IR_FSETGT:s="a";s2="b";break;
|
||||
case IR_FSETLE:s="be";s2="ae";break;
|
||||
case IR_FSETGE:s="ae";s2="be";break;
|
||||
default:return 0;
|
||||
}
|
||||
s="\tfucompp\n\tfnstsw\tax\n\tsahf\n\tset"+s+"\tal\n\tmovzx\t%l,al\n";
|
||||
s2="\tfucompp\n\tfnstsw\tax\n\tsahf\n\tset"+s2+"\tal\n\tmovzx\t%l,al\n";
|
||||
Tile *q=d_new Tile( s,s2,munchFP( t->l ),munchFP( t->r ) );
|
||||
q->want_l=EAX;
|
||||
return q;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Generic Call handling //
|
||||
///////////////////////////
|
||||
Tile *Codegen_x86::munchCall( TNode *t ){
|
||||
Tile *q;
|
||||
if( t->l->op==IR_GLOBAL ){
|
||||
q=d_new Tile( "\tcall\t"+t->l->sconst+"\n",t->r ? munchReg( t->r ) : 0 );
|
||||
}else{
|
||||
q=d_new Tile( "\tcall\t%l\n",munchReg( t->l ),t->r ? munchReg( t->r ) : 0 );
|
||||
}
|
||||
q->argFrame=t->iconst;
|
||||
q->want_l=EAX;
|
||||
q->hits=(1<<EAX)|(1<<ECX)|(1<<EDX);
|
||||
return q;
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// munch and dicard result //
|
||||
/////////////////////////////
|
||||
Tile *Codegen_x86::munch( TNode *t ){
|
||||
if( !t ) return 0;
|
||||
Tile *q=0;
|
||||
string s;
|
||||
switch( t->op ){
|
||||
case IR_JSR:
|
||||
q=d_new Tile( "\tcall\t"+t->sconst+'\n' );
|
||||
break;
|
||||
case IR_RET:
|
||||
q=d_new Tile( "\tret\n" );
|
||||
break;
|
||||
case IR_RETURN:
|
||||
q=munchReg( t->l );q->want_l=EAX;
|
||||
s="\tjmp\t"+t->sconst+'\n';
|
||||
q=d_new Tile( s,q );
|
||||
break;
|
||||
case IR_FRETURN:
|
||||
q=munchFP( t->l );
|
||||
s="\tjmp\t"+t->sconst+'\n';
|
||||
q=d_new Tile( s,q );
|
||||
break;
|
||||
case IR_CALL:
|
||||
q=munchCall( t );
|
||||
break;
|
||||
case IR_JUMP:
|
||||
q=d_new Tile( "\tjmp\t"+t->sconst+'\n' );
|
||||
break;
|
||||
case IR_JUMPT:
|
||||
if( TNode *p=t->l ){
|
||||
bool neg=false;
|
||||
if( isRelop( p->op ) ){
|
||||
string func;
|
||||
q=genCompare( p,func,neg );
|
||||
q=d_new Tile( "\tj"+func+"\t"+t->sconst+"\n",q );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IR_JUMPF:
|
||||
if( TNode *p=t->l ){
|
||||
bool neg=true;
|
||||
if( isRelop( p->op ) ){
|
||||
string func;
|
||||
q=genCompare( p,func,neg );
|
||||
q=d_new Tile( "\tj"+func+"\t"+t->sconst+"\n",q );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IR_MOVE:
|
||||
if( matchMEM( t->r,s ) ){
|
||||
string c;
|
||||
if( matchCONST( t->l,c ) ){
|
||||
q=d_new Tile( "\tmov\t"+s+","+c+"\n" );
|
||||
}else if( t->l->op==IR_ADD || t->l->op==IR_SUB ){
|
||||
TNode *p=0;
|
||||
if( nodesEqual( t->l->l,t->r ) ) p=t->l->r;
|
||||
else if( t->l->op==IR_ADD && nodesEqual( t->l->r,t->r ) ) p=t->l->l;
|
||||
if( p ){
|
||||
string c,op;
|
||||
switch( t->l->op ){
|
||||
case IR_ADD:op="\tadd\t";break;
|
||||
case IR_SUB:op="\tsub\t";break;
|
||||
}
|
||||
if( matchCONST( p,c ) ){
|
||||
q=d_new Tile( op+s+","+c+"\n" );
|
||||
}else{
|
||||
q=d_new Tile( op+s+",%l\n",munchReg( p ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !q ) q=d_new Tile( "\tmov\t"+s+",%l\n",munchReg( t->l ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
if( !q ) q=munchReg( t );
|
||||
return q;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// munch and return result in a register //
|
||||
///////////////////////////////////////////
|
||||
Tile *Codegen_x86::munchReg( TNode *t ){
|
||||
if( !t ) return 0;
|
||||
|
||||
string s;
|
||||
Tile *q=0;
|
||||
|
||||
switch( t->op ){
|
||||
case IR_JUMPT:
|
||||
q=d_new Tile( "\tand\t%l,%l\n\tjnz\t"+t->sconst+'\n',munchReg( t->l ) );
|
||||
break;
|
||||
case IR_JUMPF:
|
||||
q=d_new Tile( "\tand\t%l,%l\n\tjz\t"+t->sconst+'\n',munchReg( t->l ) );
|
||||
break;
|
||||
case IR_JUMPGE:
|
||||
q=d_new Tile( "\tcmp\t%l,%r\n\tjnc\t"+t->sconst+'\n',munchReg( t->l ),munchReg( t->r ) );
|
||||
break;
|
||||
case IR_CALL:
|
||||
q=munchCall( t );
|
||||
break;
|
||||
case IR_MOVE:
|
||||
//MUST BE MOVE TO MEM!
|
||||
if( matchMEM( t->r,s ) ){
|
||||
q=d_new Tile( "\tmov\t"+s+",%l\n",munchReg( t->l ) );
|
||||
}else if( t->r->op==IR_MEM ){
|
||||
q=d_new Tile( "\tmov\t[%r],%l\n",munchReg( t->l ),munchReg( t->r->l ) );
|
||||
}
|
||||
break;
|
||||
case IR_MEM:
|
||||
if( matchMEM( t,s ) ){
|
||||
q=d_new Tile( "\tmov\t%l,"+s+"\n" );
|
||||
}else{
|
||||
q=d_new Tile( "\tmov\t%l,[%l]\n",munchReg( t->l ) );
|
||||
}
|
||||
break;
|
||||
case IR_SEQ:
|
||||
q=d_new Tile( "",munch(t->l),munch(t->r) );
|
||||
break;
|
||||
case IR_ARG:
|
||||
q=d_new Tile( "\tlea\t%l,[esp"+itoa_sgn(t->iconst)+"]\n" );
|
||||
break;
|
||||
case IR_LOCAL:
|
||||
q=d_new Tile( "\tlea\t%l,[ebp"+itoa_sgn(t->iconst)+"]\n" );
|
||||
break;
|
||||
case IR_GLOBAL:
|
||||
q=d_new Tile( string( "\tmov\t%l," )+t->sconst+'\n' );
|
||||
break;
|
||||
case IR_CAST:
|
||||
q=munchFP( t->l );
|
||||
s="\tpush\t%l\n\tfistp\t[esp]\n\tpop\t%l\n";
|
||||
q=d_new Tile( s,q );
|
||||
break;
|
||||
case IR_CONST:
|
||||
q=d_new Tile( "\tmov\t%l,"+itoa(t->iconst)+"\n" );
|
||||
break;
|
||||
case IR_NEG:
|
||||
q=munchUnary( t );
|
||||
break;
|
||||
case IR_AND:case IR_OR:case IR_XOR:
|
||||
q=munchLogical( t );
|
||||
break;
|
||||
case IR_ADD:case IR_SUB:case IR_MUL:case IR_DIV:
|
||||
q=munchArith( t );
|
||||
break;
|
||||
case IR_SHL:case IR_SHR:case IR_SAR:
|
||||
q=munchShift( t );
|
||||
break;
|
||||
case IR_SETEQ:case IR_SETNE:case IR_SETLT:case IR_SETGT:case IR_SETLE:case IR_SETGE:
|
||||
q=munchRelop( t );
|
||||
break;
|
||||
case IR_FSETEQ:case IR_FSETNE:case IR_FSETLT:case IR_FSETGT:case IR_FSETLE:case IR_FSETGE:
|
||||
q=munchFPRelop( t );
|
||||
break;
|
||||
default:
|
||||
q=munchFP( t );if( !q ) return 0;
|
||||
s="\tpush\t%l\n\tfstp\t[esp]\n\tpop\t%l\n";
|
||||
q=d_new Tile( s,q );
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// munch and return result on FP stack //
|
||||
/////////////////////////////////////////
|
||||
Tile *Codegen_x86::munchFP( TNode *t ){
|
||||
if( !t ) return 0;
|
||||
|
||||
string s;
|
||||
Tile *q=0;
|
||||
|
||||
switch( t->op ){
|
||||
case IR_FCALL:
|
||||
q=munchCall( t );
|
||||
break;
|
||||
case IR_FCAST:
|
||||
s="\tpush\t%l\n\tfild\t[esp]\n\tpop\t%l\n";
|
||||
q=d_new Tile( s,munchReg( t->l ) );
|
||||
break;
|
||||
case IR_FNEG:
|
||||
q=munchFPUnary( t );
|
||||
break;
|
||||
case IR_FADD:case IR_FSUB:case IR_FMUL:case IR_FDIV:
|
||||
q=munchFPArith( t );
|
||||
break;
|
||||
default:
|
||||
q=munchReg( t );if( !q ) return 0;
|
||||
s="\tpush\t%l\n\tfld\t[esp]\n\tpop\t%l\n";
|
||||
q=d_new Tile( s,q );
|
||||
}
|
||||
return q;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
#include "../codegen.h"
|
||||
|
||||
struct Tile;
|
||||
|
||||
class Codegen_x86 : public Codegen{
|
||||
public:
|
||||
Codegen_x86( ostream &out,bool debug );
|
||||
|
||||
virtual void enter( const string &l,int frameSize );
|
||||
virtual void code( TNode *code );
|
||||
virtual void leave( TNode *cleanup,int pop_sz );
|
||||
virtual void label( const string &l );
|
||||
virtual void i_data( int i,const string &l );
|
||||
virtual void s_data( const string &s,const string &l );
|
||||
virtual void p_data( const string &p,const string &l );
|
||||
virtual void align_data( int n );
|
||||
virtual void flush();
|
||||
|
||||
private:
|
||||
bool inCode;
|
||||
|
||||
Tile *genCompare( TNode *t,string &func,bool negate );
|
||||
|
||||
Tile *munch( TNode *t ); //munch and discard result
|
||||
Tile *munchReg( TNode *t ); //munch and put result in a CPU reg
|
||||
Tile *munchFP( TNode *t ); //munch and put result on FP stack
|
||||
|
||||
Tile *munchCall( TNode *t );
|
||||
Tile *munchUnary( TNode *t );
|
||||
Tile *munchLogical( TNode *t );
|
||||
Tile *munchArith( TNode *t );
|
||||
Tile *munchShift( TNode *t );
|
||||
Tile *munchRelop( TNode *t );
|
||||
Tile *munchFPUnary( TNode *t );
|
||||
Tile *munchFPArith( TNode *t );
|
||||
Tile *munchFPRelop( TNode *t );
|
||||
};
|
||||
@@ -0,0 +1,273 @@
|
||||
|
||||
#include "../std.h"
|
||||
#include "codegen_x86.h"
|
||||
#include "tile.h"
|
||||
|
||||
//reduce to 3 for stress test
|
||||
static const int NUM_REGS=6;
|
||||
|
||||
static const string regs[]=
|
||||
{"???","eax","ecx","edx","edi","esi","ebx"};
|
||||
|
||||
//array of 'used' flags
|
||||
static bool regUsed[NUM_REGS+1];
|
||||
|
||||
//size of locals in function
|
||||
static int frameSize,maxFrameSize;
|
||||
|
||||
//code fragments
|
||||
static vector<string> codeFrags,dataFrags;
|
||||
|
||||
//name of function
|
||||
static string funcLabel;
|
||||
|
||||
static void resetRegs(){
|
||||
for( int n=1;n<=NUM_REGS;++n ) regUsed[n]=false;
|
||||
}
|
||||
|
||||
static int allocReg( int n ){
|
||||
if( !n || regUsed[n] ){
|
||||
for( n=NUM_REGS;n>=1 && regUsed[n];--n ){}
|
||||
if( !n ) return 0;
|
||||
}
|
||||
regUsed[n]=true;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void freeReg( int n ){
|
||||
regUsed[n]=false;
|
||||
}
|
||||
|
||||
static void pushReg( int n ){
|
||||
frameSize+=4;
|
||||
if( frameSize>maxFrameSize ) maxFrameSize=frameSize;
|
||||
char buff[32];itoa( frameSize,buff,10 );
|
||||
string s="\tmov\t[ebp-";s+=buff;s+="],";s+=regs[n];s+='\n';
|
||||
codeFrags.push_back( s );
|
||||
}
|
||||
|
||||
static void popReg( int n ){
|
||||
char buff[32];itoa( frameSize,buff,10 );
|
||||
string s="\tmov\t";s+=regs[n];s+=",[ebp-";s+=buff;s+="]\n";
|
||||
codeFrags.push_back( s );
|
||||
frameSize-=4;
|
||||
}
|
||||
|
||||
static void moveReg( int d,int s ){
|
||||
string t="\tmov\t"+regs[d]+','+regs[s]+'\n';
|
||||
codeFrags.push_back( t );
|
||||
}
|
||||
|
||||
static void swapRegs( int d,int s ){
|
||||
string t="\txchg\t"+regs[d]+','+regs[s]+'\n';
|
||||
codeFrags.push_back( t );
|
||||
}
|
||||
|
||||
Tile::Tile( const string &a,Tile *l,Tile *r )
|
||||
:assem(a),l(l),r(r),want_l(0),want_r(0),hits(0),need(0),argFrame(0){
|
||||
}
|
||||
|
||||
Tile::Tile( const string &a,const string &a2,Tile *l,Tile *r )
|
||||
:assem(a),assem2(a2),l(l),r(r),want_l(0),want_r(0),hits(0),need(0),argFrame(0){
|
||||
}
|
||||
|
||||
Tile::~Tile(){
|
||||
delete l;delete r;
|
||||
}
|
||||
|
||||
void Tile::label(){
|
||||
if( !l ){
|
||||
need=1;
|
||||
}else if( !r ){
|
||||
l->label();
|
||||
need=l->need;
|
||||
}else{
|
||||
l->label();r->label();
|
||||
if( l->need==r->need ) need=l->need+1;
|
||||
else if( l->need>r->need ) need=l->need;
|
||||
else need=r->need;
|
||||
}
|
||||
}
|
||||
|
||||
int Tile::eval( int want ){
|
||||
//save any hit registers
|
||||
int spill=hits;
|
||||
if( want_l ) spill|=1<<want_l;
|
||||
if( want_r ) spill|=1<<want_r;
|
||||
if( spill ){
|
||||
for( int n=1;n<=NUM_REGS;++n ){
|
||||
if( spill&(1<<n) ){
|
||||
if( regUsed[n] ) pushReg( n );
|
||||
else spill&=~(1<<n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if tile needs an argFrame...
|
||||
if( argFrame ){
|
||||
codeFrags.push_back( "-"+itoa(argFrame) );
|
||||
}
|
||||
|
||||
int got_l=0,got_r=0;
|
||||
if( want_l ) want=want_l;
|
||||
|
||||
string *as=&assem;
|
||||
|
||||
if( !l ){
|
||||
got_l=allocReg( want );
|
||||
}else if( !r ){
|
||||
got_l=l->eval( want );
|
||||
}else{
|
||||
if( l->need>=NUM_REGS && r->need>=NUM_REGS ){
|
||||
got_r=r->eval( 0 );
|
||||
pushReg( got_r );freeReg( got_r );
|
||||
got_l=l->eval( want );
|
||||
got_r=allocReg( want_r );popReg( got_r );
|
||||
}else if( r->need>l->need ){
|
||||
got_r=r->eval( want_r );
|
||||
got_l=l->eval( want );
|
||||
}else{
|
||||
got_l=l->eval( want );
|
||||
got_r=r->eval( want_r );
|
||||
if( assem2.size() ) as=&assem2;
|
||||
}
|
||||
if( want_l==got_r || want_r==got_l ){
|
||||
swapRegs( got_l,got_r );
|
||||
int t=got_l;got_l=got_r;got_r=t;
|
||||
}
|
||||
}
|
||||
|
||||
if( !want_l ) want_l=got_l;
|
||||
else if( want_l!=got_l ) moveReg( want_l,got_l );
|
||||
|
||||
if( !want_r ) want_r=got_r;
|
||||
else if( want_r!=got_r ) moveReg( want_r,got_r );
|
||||
|
||||
int i;
|
||||
while( (i=as->find( "%l" ))!=string::npos ) as->replace( i,2,regs[want_l] );
|
||||
while( (i=as->find( "%r" ))!=string::npos ) as->replace( i,2,regs[want_r] );
|
||||
|
||||
codeFrags.push_back( *as );
|
||||
|
||||
freeReg( got_r );
|
||||
if( want_l!=got_l ) moveReg( got_l,want_l );
|
||||
|
||||
//cleanup argFrame
|
||||
if( argFrame ){
|
||||
//***** Not needed for STDCALL *****
|
||||
// codeFrags.push_back( "+"+itoa(argFrame) );
|
||||
}
|
||||
|
||||
//restore spilled regs
|
||||
if( spill ){
|
||||
for( int n=NUM_REGS;n>=1;--n ){
|
||||
if( spill&(1<<n) ) popReg( n );
|
||||
}
|
||||
}
|
||||
return got_l;
|
||||
}
|
||||
|
||||
void Codegen_x86::flush(){
|
||||
vector<string>::iterator it;
|
||||
for( it=dataFrags.begin();it!=dataFrags.end();++it ) out<<*it;
|
||||
dataFrags.clear();
|
||||
}
|
||||
|
||||
void Codegen_x86::enter( const string &l,int frameSize ){
|
||||
|
||||
inCode=true;
|
||||
::frameSize=maxFrameSize=frameSize;
|
||||
codeFrags.clear();funcLabel=l;
|
||||
}
|
||||
|
||||
void Codegen_x86::code( TNode *stmt ){
|
||||
resetRegs();
|
||||
Tile *q=munch( stmt );
|
||||
q->label();
|
||||
q->eval( 0 );
|
||||
delete q;
|
||||
delete stmt;
|
||||
}
|
||||
|
||||
static string fixEsp( int esp_off ){
|
||||
if( esp_off<0 ) return "\tsub\tesp,"+itoa(-esp_off)+"\n";
|
||||
return "\tadd\tesp,"+itoa(esp_off)+"\n";
|
||||
}
|
||||
|
||||
void Codegen_x86::leave( TNode *cleanup,int pop_sz ){
|
||||
if( cleanup ){
|
||||
resetRegs();
|
||||
allocReg( EAX );
|
||||
Tile *q=munch( cleanup );
|
||||
q->label();
|
||||
q->eval( 0 );
|
||||
delete q;
|
||||
}
|
||||
|
||||
out<<"\t.align\t16\n";
|
||||
|
||||
if( funcLabel.size() ) out<<funcLabel<<'\n';
|
||||
|
||||
out<<"\tpush\tebx\n";
|
||||
out<<"\tpush\tesi\n";
|
||||
out<<"\tpush\tedi\n";
|
||||
out<<"\tpush\tebp\n";
|
||||
out<<"\tmov\tebp,esp\n";
|
||||
if( maxFrameSize ) out<<"\tsub\tesp,"<<maxFrameSize<<'\n';
|
||||
|
||||
int esp_off=0;
|
||||
vector<string>::iterator it=codeFrags.begin();
|
||||
for( it=codeFrags.begin();it!=codeFrags.end();++it ){
|
||||
const string &t=*it;
|
||||
if( t[0]=='+' ){
|
||||
esp_off+=atoi(t.substr(1));
|
||||
}else if( t[0]=='-' ){
|
||||
//***** Still needed for STDCALL *****
|
||||
esp_off-=atoi(t.substr(1));
|
||||
}else{
|
||||
if( esp_off ){
|
||||
out<<fixEsp( esp_off );
|
||||
esp_off=0;
|
||||
}
|
||||
out<<*it;
|
||||
}
|
||||
}
|
||||
if( esp_off ) out<<fixEsp( esp_off );
|
||||
|
||||
out<<"\tmov\tesp,ebp\n";
|
||||
out<<"\tpop\tebp\n";
|
||||
out<<"\tpop\tedi\n";
|
||||
out<<"\tpop\tesi\n";
|
||||
out<<"\tpop\tebx\n";
|
||||
out<<"\tret\tword "<<pop_sz<<"\n";
|
||||
|
||||
delete cleanup;
|
||||
inCode=false;
|
||||
}
|
||||
|
||||
void Codegen_x86::label( const string &l ){
|
||||
string t=l+'\n';
|
||||
if( inCode ) codeFrags.push_back( t );
|
||||
else dataFrags.push_back( t );
|
||||
}
|
||||
|
||||
void Codegen_x86::align_data( int n ){
|
||||
char buff[32];itoa( n,buff,10 );
|
||||
dataFrags.push_back( string( "\t.align\t" )+buff+'\n' );
|
||||
}
|
||||
|
||||
void Codegen_x86::i_data( int i,const string &l ){
|
||||
if( l.size() ) dataFrags.push_back( l );
|
||||
char buff[32];itoa( i,buff,10 );
|
||||
dataFrags.push_back( string( "\t.dd\t" )+buff+'\n' );
|
||||
}
|
||||
|
||||
void Codegen_x86::s_data( const string &s,const string &l ){
|
||||
if( l.size() ) dataFrags.push_back( l );
|
||||
dataFrags.push_back( string( "\t.db\t\"" )+s+"\",0\n" );
|
||||
}
|
||||
|
||||
void Codegen_x86::p_data( const string &p,const string &l ){
|
||||
if( l.size() ) dataFrags.push_back( l );
|
||||
dataFrags.push_back( string( "\t.dd\t" )+p+'\n' );
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
#ifndef TILE_H
|
||||
#define TILE_H
|
||||
|
||||
enum{ EAX=1,ECX,EDX,EDI,ESI,EBX };
|
||||
|
||||
struct Tile{
|
||||
|
||||
int want_l,want_r,hits,argFrame;
|
||||
|
||||
Tile( const string &a,Tile *l=0,Tile *r=0 );
|
||||
Tile( const string &a,const string &a2,Tile *l=0,Tile *r=0 );
|
||||
~Tile();
|
||||
|
||||
void label();
|
||||
int eval( int want );
|
||||
|
||||
private:
|
||||
int need;
|
||||
Tile *l,*r;
|
||||
string assem,assem2;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,376 @@
|
||||
# Microsoft Developer Studio Project File - Name="compiler" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=compiler - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "compiler.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "compiler.mak" CFG="compiler - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "compiler - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "compiler - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "compiler - Win32 Blitz3DRelease" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "compiler - Win32 Blitz2DRelease" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "compiler - Win32 Blitz3DEdu" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "compiler - Win32 Blitz3DDemo" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "compiler - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "compiler - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /GZ /c
|
||||
# SUBTRACT CPP /Gy
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "compiler - Win32 Blitz3DRelease"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "compiler___Win32_Blitz3DRelease"
|
||||
# PROP BASE Intermediate_Dir "compiler___Win32_Blitz3DRelease"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "compiler___Win32_Blitz3DRelease"
|
||||
# PROP Intermediate_Dir "compiler___Win32_Blitz3DRelease"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c
|
||||
# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "compiler - Win32 Blitz2DRelease"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "compiler___Win32_Blitz2DRelease"
|
||||
# PROP BASE Intermediate_Dir "compiler___Win32_Blitz2DRelease"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "compiler___Win32_Blitz2DRelease"
|
||||
# PROP Intermediate_Dir "compiler___Win32_Blitz2DRelease"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "compiler - Win32 Blitz3DEdu"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "compiler___Win32_Blitz3DEdu"
|
||||
# PROP BASE Intermediate_Dir "compiler___Win32_Blitz3DEdu"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "compiler___Win32_Blitz3DEdu"
|
||||
# PROP Intermediate_Dir "compiler___Win32_Blitz3DEdu"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c
|
||||
# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /Yu"std.h" /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "compiler - Win32 Blitz3DDemo"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "compiler___Win32_Blitz3DDemo"
|
||||
# PROP BASE Intermediate_Dir "compiler___Win32_Blitz3DDemo"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "compiler___Win32_Blitz3DDemo"
|
||||
# PROP Intermediate_Dir "compiler___Win32_Blitz3DDemo"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c
|
||||
# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /Yu"std.h" /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "compiler - Win32 Release"
|
||||
# Name "compiler - Win32 Debug"
|
||||
# Name "compiler - Win32 Blitz3DRelease"
|
||||
# Name "compiler - Win32 Blitz2DRelease"
|
||||
# Name "compiler - Win32 Blitz3DEdu"
|
||||
# Name "compiler - Win32 Blitz3DDemo"
|
||||
# Begin Group "nodes"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\declnode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\declnode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\exprnode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\exprnode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\node.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\node.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\nodes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\prognode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\prognode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stmtnode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stmtnode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\varnode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\varnode.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "environ"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\decl.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\decl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\environ.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\environ.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\label.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\type.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\type.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "parser"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\parser.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\parser.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\toker.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\toker.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "codegen"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "codegen_x86"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\codegen_x86\codegen_x86.cpp
|
||||
# ADD CPP /Yu"../std.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\codegen_x86\codegen_x86.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\codegen_x86\tile.cpp
|
||||
# ADD CPP /Yu"../std.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\codegen_x86\tile.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\codegen.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "assem"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "assem_x86"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\assem_x86\asm_insts.cpp
|
||||
# ADD CPP /Yu"../std.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\assem_x86\assem_x86.cpp
|
||||
# ADD CPP /Yu"../std.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\assem_x86\assem_x86.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\assem_x86\insts.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\assem_x86\operand.cpp
|
||||
# ADD CPP /Yu"../std.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\assem_x86\operand.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\assem.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ex.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\std.cpp
|
||||
# ADD CPP /Yc"std.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\std.h
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "decl.h"
|
||||
#include "type.h"
|
||||
|
||||
Decl::~Decl(){
|
||||
}
|
||||
|
||||
DeclSeq::DeclSeq(){
|
||||
}
|
||||
|
||||
void Decl::getName( char *buff ){
|
||||
int sz=name.size();
|
||||
memcpy( buff,name.data(),sz );
|
||||
buff[sz]=0;
|
||||
}
|
||||
|
||||
DeclSeq::~DeclSeq(){
|
||||
for( ;decls.size();decls.pop_back() ) delete decls.back();
|
||||
}
|
||||
|
||||
Decl *DeclSeq::findDecl( const string &s ){
|
||||
vector<Decl*>::iterator it;
|
||||
for( it=decls.begin();it!=decls.end();++it ){
|
||||
if( (*it)->name==s ) return *it;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Decl *DeclSeq::insertDecl( const string &s,Type *t,int kind,ConstType *d ){
|
||||
if( findDecl( s ) ) return 0;
|
||||
decls.push_back( d_new Decl( s,t,kind,d ) );
|
||||
return decls.back();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
#ifndef DECL_H
|
||||
#define DECL_H
|
||||
|
||||
enum{
|
||||
DECL_FUNC=1,DECL_ARRAY=2,DECL_STRUCT=4, //NOT vars
|
||||
DECL_GLOBAL=8,DECL_LOCAL=16,DECL_PARAM=32,DECL_FIELD=64 //ARE vars
|
||||
};
|
||||
|
||||
struct Type;
|
||||
struct ConstType;
|
||||
|
||||
struct Decl{
|
||||
string name;
|
||||
Type *type; //type
|
||||
int kind,offset;
|
||||
ConstType *defType; //default value
|
||||
Decl( const string &s,Type *t,int k,ConstType *d=0 ):name(s),type(t),kind(k),defType(d){}
|
||||
~Decl();
|
||||
|
||||
virtual void getName( char *buff );
|
||||
};
|
||||
|
||||
struct DeclSeq{
|
||||
vector<Decl*> decls;
|
||||
DeclSeq();
|
||||
~DeclSeq();
|
||||
Decl *findDecl( const string &s );
|
||||
Decl *insertDecl( const string &s,Type *t,int kind,ConstType *d=0 );
|
||||
int size(){ return decls.size(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
#ifndef DECL_H
|
||||
#define DECL_H
|
||||
|
||||
#include "type.h"
|
||||
|
||||
const int OFFSET_GLOBAL=0x80000000;
|
||||
|
||||
struct Decl{
|
||||
int offset;
|
||||
Type *type;
|
||||
Decl( int n,Type *t ):offset(n),type(t){}
|
||||
virtual Decl *Decl(){ return 0; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,280 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "nodes.h"
|
||||
|
||||
//////////////////////////////
|
||||
// Sequence of declarations //
|
||||
//////////////////////////////
|
||||
void DeclSeqNode::proto( DeclSeq *d,Environ *e ){
|
||||
for( int k=0;k<decls.size();++k ){
|
||||
try{ decls[k]->proto( d,e ); }
|
||||
catch( Ex &x ){
|
||||
if( x.pos<0 ) x.pos=decls[k]->pos;
|
||||
if(!x.file.size() ) x.file=decls[k]->file;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclSeqNode::semant( Environ *e ){
|
||||
for( int k=0;k<decls.size();++k ){
|
||||
try{ decls[k]->semant( e ); }
|
||||
catch( Ex &x ){
|
||||
if( x.pos<0 ) x.pos=decls[k]->pos;
|
||||
if(!x.file.size() ) x.file=decls[k]->file;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclSeqNode::translate( Codegen *g ){
|
||||
for( int k=0;k<decls.size();++k ){
|
||||
try{ decls[k]->translate( g ); }
|
||||
catch( Ex &x ){
|
||||
if( x.pos<0 ) x.pos=decls[k]->pos;
|
||||
if(!x.file.size() ) x.file=decls[k]->file;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclSeqNode::transdata( Codegen *g ){
|
||||
for( int k=0;k<decls.size();++k ){
|
||||
try{ decls[k]->transdata( g ); }
|
||||
catch( Ex &x ){
|
||||
if( x.pos<0 ) x.pos=decls[k]->pos;
|
||||
if(!x.file.size() ) x.file=decls[k]->file;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Simple var declaration //
|
||||
////////////////////////////
|
||||
void VarDeclNode::proto( DeclSeq *d,Environ *e ){
|
||||
|
||||
Type *ty=tagType( tag,e );
|
||||
if( !ty ) ty=Type::int_type;
|
||||
ConstType *defType=0;
|
||||
|
||||
if( expr ){
|
||||
expr=expr->semant( e );
|
||||
expr=expr->castTo( ty,e );
|
||||
if( constant || (kind&DECL_PARAM) ){
|
||||
ConstNode *c=expr->constNode();
|
||||
if( !c ) ex( "Expression must be constant" );
|
||||
if( ty==Type::int_type ) ty=d_new ConstType( c->intValue() );
|
||||
else if( ty==Type::float_type ) ty=d_new ConstType( c->floatValue() );
|
||||
else ty=d_new ConstType( c->stringValue() );
|
||||
e->types.push_back( ty );
|
||||
delete expr;expr=0;
|
||||
}
|
||||
if( kind&DECL_PARAM ){
|
||||
defType=ty->constType();ty=defType->valueType;
|
||||
}
|
||||
}else if( constant ) ex( "Constants must be initialized" );
|
||||
|
||||
Decl *decl=d->insertDecl( ident,ty,kind,defType );
|
||||
if( !decl ) ex( "Duplicate variable name" );
|
||||
if( expr ) sem_var=d_new DeclVarNode( decl );
|
||||
}
|
||||
|
||||
void VarDeclNode::semant( Environ *e ){
|
||||
}
|
||||
|
||||
void VarDeclNode::translate( Codegen *g ){
|
||||
if( kind & DECL_GLOBAL ){
|
||||
g->align_data( 4 );
|
||||
g->i_data( 0,"_v"+ident );
|
||||
}
|
||||
if( expr ) g->code( sem_var->store( g,expr->translate( g ) ) );
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
// Function Declaration //
|
||||
//////////////////////////
|
||||
void FuncDeclNode::proto( DeclSeq *d,Environ *e ){
|
||||
Type *t=tagType( tag,e );if( !t ) t=Type::int_type;
|
||||
a_ptr<DeclSeq> decls( d_new DeclSeq() );
|
||||
params->proto( decls,e );
|
||||
sem_type=d_new FuncType( t,decls.release(),false,false );
|
||||
if( !d->insertDecl( ident,sem_type,DECL_FUNC ) ){
|
||||
delete sem_type;ex( "duplicate identifier" );
|
||||
}
|
||||
e->types.push_back( sem_type );
|
||||
}
|
||||
|
||||
void FuncDeclNode::semant( Environ *e ){
|
||||
|
||||
sem_env=d_new Environ( genLabel(),sem_type->returnType,1,e );
|
||||
DeclSeq *decls=sem_env->decls;
|
||||
|
||||
int k;
|
||||
for( k=0;k<sem_type->params->size();++k ){
|
||||
Decl *d=sem_type->params->decls[k];
|
||||
if( !decls->insertDecl( d->name,d->type,d->kind ) ) ex( "duplicate identifier" );
|
||||
}
|
||||
|
||||
stmts->semant( sem_env );
|
||||
}
|
||||
|
||||
void FuncDeclNode::translate( Codegen *g ){
|
||||
|
||||
//var offsets
|
||||
int size=enumVars( sem_env );
|
||||
|
||||
//enter function
|
||||
g->enter( "_f"+ident,size );
|
||||
|
||||
//initialize locals
|
||||
TNode *t=createVars( sem_env );
|
||||
if( t ) g->code( t );
|
||||
if( g->debug ){
|
||||
string t=genLabel();
|
||||
g->s_data( ident,t );
|
||||
g->code( call( "__bbDebugEnter",local(0),iconst((int)sem_env),global(t) ) );
|
||||
}
|
||||
|
||||
//translate statements
|
||||
stmts->translate( g );
|
||||
|
||||
for( int k=0;k<sem_env->labels.size();++k ){
|
||||
if( sem_env->labels[k]->def<0 ) ex( "Undefined label",sem_env->labels[k]->ref );
|
||||
}
|
||||
|
||||
//leave the function
|
||||
g->label( sem_env->funcLabel+"_leave" );
|
||||
t=deleteVars( sem_env );
|
||||
if( g->debug ) t=d_new TNode( IR_SEQ,call( "__bbDebugLeave" ),t );
|
||||
g->leave( t,sem_type->params->size()*4 );
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Type Declaration //
|
||||
//////////////////////
|
||||
void StructDeclNode::proto( DeclSeq *d,Environ *e ){
|
||||
sem_type=d_new StructType( ident,d_new DeclSeq() );
|
||||
if( !d->insertDecl( ident,sem_type,DECL_STRUCT ) ){
|
||||
delete sem_type;ex( "Duplicate identifier" );
|
||||
}
|
||||
e->types.push_back( sem_type );
|
||||
}
|
||||
|
||||
void StructDeclNode::semant( Environ *e ){
|
||||
fields->proto( sem_type->fields,e );
|
||||
for( int k=0;k<sem_type->fields->size();++k ) sem_type->fields->decls[k]->offset=k*4;
|
||||
}
|
||||
|
||||
void StructDeclNode::translate( Codegen *g ){
|
||||
|
||||
//translate fields
|
||||
fields->translate( g );
|
||||
|
||||
//type ID
|
||||
g->align_data( 4 );
|
||||
g->i_data( 5,"_t"+ident );
|
||||
|
||||
//used and free lists for type
|
||||
int k;
|
||||
for( k=0;k<2;++k ){
|
||||
string lab=genLabel();
|
||||
g->i_data( 0,lab ); //fields
|
||||
g->p_data( lab ); //next
|
||||
g->p_data( lab ); //prev
|
||||
g->i_data( 0 ); //type
|
||||
g->i_data( -1 ); //ref_cnt
|
||||
}
|
||||
|
||||
//number of fields
|
||||
g->i_data( sem_type->fields->size() );
|
||||
|
||||
//type of each field
|
||||
for( k=0;k<sem_type->fields->size();++k ){
|
||||
Decl *field=sem_type->fields->decls[k];
|
||||
Type *type=field->type;
|
||||
string t;
|
||||
if( type==Type::int_type ) t="__bbIntType";
|
||||
else if( type==Type::float_type ) t="__bbFltType";
|
||||
else if( type==Type::string_type ) t="__bbStrType";
|
||||
else if( StructType *s=type->structType() ) t="_t"+s->ident;
|
||||
else if( VectorType *v=type->vectorType() ) t=v->label;
|
||||
g->p_data( t );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Data declaration //
|
||||
//////////////////////
|
||||
void DataDeclNode::proto( DeclSeq *d,Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
ConstNode *c=expr->constNode();
|
||||
if( !c ) ex( "Data expression must be constant" );
|
||||
if( expr->sem_type==Type::string_type ) str_label=genLabel();
|
||||
}
|
||||
|
||||
void DataDeclNode::semant( Environ *e ){
|
||||
}
|
||||
|
||||
void DataDeclNode::translate( Codegen *g ){
|
||||
if( expr->sem_type!=Type::string_type ) return;
|
||||
ConstNode *c=expr->constNode();
|
||||
g->s_data( c->stringValue(),str_label );
|
||||
}
|
||||
|
||||
void DataDeclNode::transdata( Codegen *g ){
|
||||
ConstNode *c=expr->constNode();
|
||||
if( expr->sem_type==Type::int_type ){
|
||||
g->i_data( 1 );g->i_data( c->intValue() );
|
||||
}else if( expr->sem_type==Type::float_type ){
|
||||
float n=c->floatValue();
|
||||
g->i_data( 2 );g->i_data( *(int*)&n );
|
||||
}else{
|
||||
g->i_data( 4 );g->p_data( str_label );
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// Vector declaration //
|
||||
////////////////////////
|
||||
void VectorDeclNode::proto( DeclSeq *d,Environ *env ){
|
||||
|
||||
Type *ty=tagType( tag,env );if( !ty ) ty=Type::int_type;
|
||||
|
||||
vector<int> sizes;
|
||||
for( int k=0;k<exprs->size();++k ){
|
||||
ExprNode *e=exprs->exprs[k]=exprs->exprs[k]->semant( env );
|
||||
ConstNode *c=e->constNode();
|
||||
if( !c ) ex( "Blitz array sizes must be constant" );
|
||||
int n=c->intValue();
|
||||
if( n<0 ) ex( "Blitz array sizes must not be negative" );
|
||||
sizes.push_back( n+1 );
|
||||
}
|
||||
string label=genLabel();
|
||||
sem_type=d_new VectorType( label,ty,sizes );
|
||||
if( !d->insertDecl( ident,sem_type,kind ) ){
|
||||
delete sem_type;ex( "Duplicate identifier" );
|
||||
}
|
||||
env->types.push_back( sem_type );
|
||||
}
|
||||
|
||||
void VectorDeclNode::translate( Codegen *g ){
|
||||
//type tag!
|
||||
g->align_data( 4 );
|
||||
VectorType *v=sem_type->vectorType();
|
||||
g->i_data( 6,v->label );
|
||||
int sz=1;
|
||||
for( int k=0;k<v->sizes.size();++k ) sz*=v->sizes[k];
|
||||
g->i_data( sz );
|
||||
string t;
|
||||
Type *type=v->elementType;
|
||||
if( type==Type::int_type ) t="__bbIntType";
|
||||
else if( type==Type::float_type ) t="__bbFltType";
|
||||
else if( type==Type::string_type ) t="__bbStrType";
|
||||
else if( StructType *s=type->structType() ) t="_t"+s->ident;
|
||||
else if( VectorType *v=type->vectorType() ) t=v->label;
|
||||
g->p_data( t );
|
||||
|
||||
if( kind==DECL_GLOBAL ) g->i_data( 0,"_v"+ident );
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
#ifndef DECLNODE_H
|
||||
#define DECLNODE_H
|
||||
|
||||
struct DeclNode : public Node{
|
||||
int pos;
|
||||
string file;
|
||||
DeclNode():pos(-1){}
|
||||
virtual void proto( DeclSeq *d,Environ *e ){}
|
||||
virtual void semant( Environ *e ){}
|
||||
virtual void translate( Codegen *g ){}
|
||||
virtual void transdata( Codegen *g ){}
|
||||
};
|
||||
|
||||
struct DeclSeqNode : public Node{
|
||||
vector<DeclNode*> decls;
|
||||
DeclSeqNode(){}
|
||||
~DeclSeqNode(){ for(;decls.size();decls.pop_back())delete decls.back(); }
|
||||
void proto( DeclSeq *d,Environ *e );
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
void transdata( Codegen *g );
|
||||
void push_back( DeclNode *d ){ decls.push_back( d ); }
|
||||
int size(){ return decls.size(); }
|
||||
};
|
||||
|
||||
#include "exprnode.h"
|
||||
#include "stmtnode.h"
|
||||
|
||||
//'kind' shouldn't really be in Parser...
|
||||
//should probably be LocalDeclNode,GlobalDeclNode,ParamDeclNode
|
||||
struct VarDeclNode : public DeclNode{
|
||||
string ident,tag;
|
||||
int kind;bool constant;
|
||||
ExprNode *expr;
|
||||
DeclVarNode *sem_var;
|
||||
VarDeclNode( const string &i,const string &t,int k,bool c,ExprNode *e ):ident(i),tag(t),kind(k),constant(c),expr(e),sem_var(0){}
|
||||
~VarDeclNode(){ delete expr;delete sem_var; }
|
||||
void proto( DeclSeq *d,Environ *e );
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct FuncDeclNode : public DeclNode{
|
||||
string ident,tag;
|
||||
DeclSeqNode *params;
|
||||
StmtSeqNode *stmts;
|
||||
FuncType *sem_type;
|
||||
Environ *sem_env;
|
||||
FuncDeclNode( const string &i,const string &t,DeclSeqNode *p,StmtSeqNode *ss ):ident(i),tag(t),params(p),stmts(ss){}
|
||||
~FuncDeclNode(){ delete params;delete stmts; }
|
||||
void proto( DeclSeq *d,Environ *e );
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct StructDeclNode : public DeclNode{
|
||||
string ident;
|
||||
DeclSeqNode *fields;
|
||||
StructType *sem_type;
|
||||
StructDeclNode( const string &i,DeclSeqNode *f ):ident(i),fields(f){}
|
||||
~StructDeclNode(){ delete fields; }
|
||||
void proto( DeclSeq *d,Environ *e );
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct DataDeclNode : public DeclNode{
|
||||
ExprNode *expr;
|
||||
string str_label;
|
||||
DataDeclNode( ExprNode *e ):expr(e){}
|
||||
~DataDeclNode(){ delete expr; }
|
||||
void proto( DeclSeq *d,Environ *e );
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
void transdata( Codegen *g );
|
||||
};
|
||||
|
||||
struct VectorDeclNode : public DeclNode{
|
||||
string ident,tag;
|
||||
ExprSeqNode *exprs;
|
||||
int kind;
|
||||
VectorType *sem_type;
|
||||
VectorDeclNode( const string &i,const string &t,ExprSeqNode *e,int k ):ident(i),tag(t),exprs(e),kind(k){}
|
||||
~VectorDeclNode(){ delete exprs; }
|
||||
void proto( DeclSeq *d,Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "environ.h"
|
||||
|
||||
Environ::Environ( const string &f,Type *r,int l,Environ *gs )
|
||||
:funcLabel(f),returnType(r),level(l),globals(gs){
|
||||
decls=d_new DeclSeq();
|
||||
typeDecls=d_new DeclSeq();
|
||||
funcDecls=d_new DeclSeq();
|
||||
if( globals ) globals->children.push_back( this );
|
||||
}
|
||||
|
||||
Environ::~Environ(){
|
||||
if( globals ) globals->children.remove( this );
|
||||
while( children.size() ) delete children.back();
|
||||
for( ;labels.size();labels.pop_back() ) delete labels.back();
|
||||
|
||||
//delete all types
|
||||
delete decls;
|
||||
delete funcDecls;
|
||||
delete typeDecls;
|
||||
|
||||
for( int k=0;k<types.size();++k ) delete types[k];
|
||||
}
|
||||
|
||||
Decl *Environ::findDecl( const string &s ){
|
||||
for( Environ *e=this;e;e=e->globals ){
|
||||
if( Decl *d=e->decls->findDecl( s ) ){
|
||||
if( d->kind&(DECL_LOCAL|DECL_PARAM) ){
|
||||
if( e==this ) return d;
|
||||
}else return d;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Decl *Environ::findFunc( const string &s ){
|
||||
for( Environ *e=this;e;e=e->globals ){
|
||||
if( Decl *d=e->funcDecls->findDecl( s ) ) return d;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Type *Environ::findType( const string &s ){
|
||||
if( s=="%" ) return Type::int_type;
|
||||
if( s=="#" ) return Type::float_type;
|
||||
if( s=="$" ) return Type::string_type;
|
||||
for( Environ *e=this;e;e=e->globals ){
|
||||
if( Decl *d=e->typeDecls->findDecl( s ) ) return d->type->structType();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Label *Environ::findLabel( const string &s ){
|
||||
for( int k=0;k<labels.size();++k ) if( labels[k]->name==s ) return labels[k];
|
||||
return 0;
|
||||
}
|
||||
|
||||
Label *Environ::insertLabel( const string &s,int def,int src,int sz ){
|
||||
Label *l=d_new Label( s,def,src,sz );
|
||||
labels.push_back( l );return l;
|
||||
}
|
||||
|
||||
string Environ::setBreak( const string &s ){
|
||||
string t=breakLabel;
|
||||
breakLabel=s;return t;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
/*
|
||||
|
||||
An environ represent a stack frame block.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ENVIRON_H
|
||||
#define ENVIRON_H
|
||||
|
||||
#include "type.h"
|
||||
#include "decl.h"
|
||||
#include "label.h"
|
||||
|
||||
class Environ{
|
||||
public:
|
||||
int level;
|
||||
DeclSeq *decls;
|
||||
DeclSeq *funcDecls;
|
||||
DeclSeq *typeDecls;
|
||||
|
||||
vector<Type*> types;
|
||||
|
||||
vector<Label*> labels;
|
||||
Environ *globals;
|
||||
Type *returnType;
|
||||
string funcLabel,breakLabel;
|
||||
list<Environ*> children; //for delete!
|
||||
|
||||
Environ( const string &f,Type *r,int l,Environ *gs );
|
||||
~Environ();
|
||||
|
||||
Decl *findDecl( const string &s );
|
||||
Decl *findFunc( const string &s );
|
||||
Type *findType( const string &s );
|
||||
Label *findLabel( const string &s );
|
||||
Label *insertLabel( const string &s,int def,int src,int sz );
|
||||
|
||||
string setBreak( const string &s );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
#ifndef EX_H
|
||||
#define EX_H
|
||||
|
||||
struct Ex{
|
||||
string ex; //what happened
|
||||
int pos; //source offset
|
||||
string file;
|
||||
Ex( const string &ex ):ex(ex),pos(-1){}
|
||||
Ex( const string &ex,int pos,const string &t ):ex(ex),pos(pos),file(t){}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,627 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "nodes.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
//////////////////////////////////
|
||||
// Cast an expression to a type //
|
||||
//////////////////////////////////
|
||||
ExprNode *ExprNode::castTo( Type *ty,Environ *e ){
|
||||
if( !sem_type->canCastTo( ty ) ){
|
||||
ex( "Illegal type conversion" );
|
||||
}
|
||||
|
||||
ExprNode *cast=d_new CastNode( this,ty );
|
||||
return cast->semant( e );
|
||||
}
|
||||
|
||||
ExprNode *CastNode::semant( Environ *e ){
|
||||
if( !expr->sem_type ){
|
||||
expr=expr->semant( e );
|
||||
}
|
||||
|
||||
if( ConstNode *c=expr->constNode() ){
|
||||
ExprNode *e;
|
||||
if( type==Type::int_type ) e=d_new IntConstNode( c->intValue() );
|
||||
else if( type==Type::float_type ) e=d_new FloatConstNode( c->floatValue() );
|
||||
else e=d_new StringConstNode( c->stringValue() );
|
||||
delete this;
|
||||
return e;
|
||||
}
|
||||
|
||||
sem_type=type;
|
||||
return this;
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// Cast an expression to a type //
|
||||
//////////////////////////////////
|
||||
TNode *CastNode::translate( Codegen *g ){
|
||||
TNode *t=expr->translate( g );
|
||||
if( expr->sem_type==Type::float_type && sem_type==Type::int_type ){
|
||||
//float->int
|
||||
return d_new TNode( IR_CAST,t,0 );
|
||||
}
|
||||
if( expr->sem_type==Type::int_type && sem_type==Type::float_type ){
|
||||
//int->float
|
||||
return d_new TNode( IR_FCAST,t,0 );
|
||||
}
|
||||
if( expr->sem_type==Type::string_type && sem_type==Type::int_type ){
|
||||
//str->int
|
||||
return call( "__bbStrToInt",t );
|
||||
}
|
||||
if( expr->sem_type==Type::int_type && sem_type==Type::string_type ){
|
||||
//int->str
|
||||
return call( "__bbStrFromInt",t );
|
||||
}
|
||||
if( expr->sem_type==Type::string_type && sem_type==Type::float_type ){
|
||||
//str->float
|
||||
return fcall( "__bbStrToFloat",t );
|
||||
}
|
||||
if( expr->sem_type==Type::float_type && sem_type==Type::string_type ){
|
||||
//float->str
|
||||
return call( "__bbStrFromFloat",t );
|
||||
}
|
||||
if( expr->sem_type->structType() && sem_type==Type::string_type ){
|
||||
//obj->str
|
||||
return call( "__bbObjToStr",t );
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// Sequence of Expressions //
|
||||
/////////////////////////////
|
||||
void ExprSeqNode::semant( Environ *e ){
|
||||
for( int k=0;k<exprs.size();++k ){
|
||||
if( exprs[k] ) exprs[k]=exprs[k]->semant( e );
|
||||
}
|
||||
}
|
||||
|
||||
TNode *ExprSeqNode::translate( Codegen *g,bool cfunc ){
|
||||
TNode *t=0,*l=0;
|
||||
for( int k=0;k<exprs.size();++k ){
|
||||
|
||||
TNode *q=exprs[k]->translate(g);
|
||||
|
||||
if( cfunc ){
|
||||
Type *ty=exprs[k]->sem_type;
|
||||
if( ty->stringType() ){
|
||||
q=call( "__bbStrToCStr",q );
|
||||
}else if( ty->structType() ){
|
||||
q=d_new TNode( IR_MEM,q );
|
||||
}else if( ty==Type::void_type ){
|
||||
q=d_new TNode( IR_MEM,add(q,iconst(4)) );
|
||||
}
|
||||
}
|
||||
|
||||
TNode *p;
|
||||
p=d_new TNode( IR_ARG,0,0,k*4 );
|
||||
p=d_new TNode( IR_MEM,p,0 );
|
||||
p=d_new TNode( IR_MOVE,q,p );
|
||||
p=d_new TNode( IR_SEQ,p,0 );
|
||||
if( l ) l->r=p;
|
||||
else t=p;
|
||||
l=p;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void ExprSeqNode::castTo( DeclSeq *decls,Environ *e,bool cfunc ){
|
||||
if( exprs.size()>decls->size() ) ex( "Too many parameters" );
|
||||
for( int k=0;k<decls->size();++k ){
|
||||
Decl *d=decls->decls[k];
|
||||
if( k<exprs.size() && exprs[k] ){
|
||||
|
||||
if( cfunc && d->type->structType() ){
|
||||
if( exprs[k]->sem_type->structType() ){
|
||||
}else if( exprs[k]->sem_type->intType() ){
|
||||
exprs[k]->sem_type=Type::void_type;
|
||||
}else{
|
||||
ex( "Illegal type conversion" );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
exprs[k]=exprs[k]->castTo( d->type,e );
|
||||
|
||||
}else{
|
||||
if( !d->defType ) ex( "Not enough parameters" );
|
||||
ExprNode *expr=constValue( d->defType );
|
||||
if( k<exprs.size() ) exprs[k]=expr;
|
||||
else exprs.push_back( expr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExprSeqNode::castTo( Type *t,Environ *e ){
|
||||
for( int k=0;k<exprs.size();++k ){
|
||||
exprs[k]=exprs[k]->castTo( t,e );
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// Function call //
|
||||
///////////////////
|
||||
ExprNode *CallNode::semant( Environ *e ){
|
||||
Type *t=e->findType( tag );
|
||||
sem_decl=e->findFunc( ident );
|
||||
if( !sem_decl || !(sem_decl->kind & DECL_FUNC) ) ex( "Function '"+ident+"' not found" );
|
||||
FuncType *f=sem_decl->type->funcType();
|
||||
if( t && f->returnType!=t ) ex( "incorrect function return type" );
|
||||
exprs->semant( e );
|
||||
exprs->castTo( f->params,e,f->cfunc );
|
||||
sem_type=f->returnType;
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *CallNode::translate( Codegen *g ){
|
||||
|
||||
FuncType *f=sem_decl->type->funcType();
|
||||
|
||||
TNode *t;
|
||||
TNode *l=global( "_f"+ident );
|
||||
TNode *r=exprs->translate( g,f->cfunc );
|
||||
|
||||
if( f->userlib ){
|
||||
l=d_new TNode( IR_MEM,l );
|
||||
usedfuncs.insert( ident );
|
||||
}
|
||||
|
||||
if( sem_type==Type::float_type ){
|
||||
t=d_new TNode( IR_FCALL,l,r,exprs->size()*4 );
|
||||
}else{
|
||||
t=d_new TNode( IR_CALL,l,r,exprs->size()*4 );
|
||||
}
|
||||
|
||||
if( f->returnType->stringType() ){
|
||||
if( f->cfunc ){
|
||||
t=call( "__bbCStrToStr",t );
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// Variable expression //
|
||||
/////////////////////////
|
||||
ExprNode *VarExprNode::semant( Environ *e ){
|
||||
var->semant( e );
|
||||
sem_type=var->sem_type;
|
||||
ConstType *c=sem_type->constType();
|
||||
if( !c ) return this;
|
||||
ExprNode *expr=constValue( c );
|
||||
delete this;return expr;
|
||||
}
|
||||
|
||||
TNode *VarExprNode::translate( Codegen *g ){
|
||||
return var->load( g );
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Integer constant //
|
||||
//////////////////////
|
||||
IntConstNode::IntConstNode( int n ):value(n){
|
||||
sem_type=Type::int_type;
|
||||
}
|
||||
|
||||
TNode *IntConstNode::translate( Codegen *g ){
|
||||
return d_new TNode( IR_CONST,0,0,value );
|
||||
}
|
||||
|
||||
int IntConstNode::intValue(){
|
||||
return value;
|
||||
}
|
||||
|
||||
float IntConstNode::floatValue(){
|
||||
return value;
|
||||
}
|
||||
|
||||
string IntConstNode::stringValue(){
|
||||
return itoa( value );
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Float constant //
|
||||
////////////////////
|
||||
FloatConstNode::FloatConstNode( float f ):value(f){
|
||||
sem_type=Type::float_type;
|
||||
}
|
||||
|
||||
TNode *FloatConstNode::translate( Codegen *g ){
|
||||
return d_new TNode( IR_CONST,0,0,*(int*)&value );
|
||||
}
|
||||
|
||||
int FloatConstNode::intValue(){
|
||||
float flt=value;
|
||||
int temp;
|
||||
_control87( _RC_NEAR|_PC_24|_EM_INVALID|_EM_ZERODIVIDE|_EM_OVERFLOW|_EM_UNDERFLOW|_EM_INEXACT|_EM_DENORMAL,0xfffff );
|
||||
_asm{
|
||||
fld [flt];
|
||||
fistp [temp];
|
||||
}
|
||||
_control87( _CW_DEFAULT,0xfffff );
|
||||
return temp;
|
||||
}
|
||||
|
||||
float FloatConstNode::floatValue(){
|
||||
return value;
|
||||
}
|
||||
|
||||
string FloatConstNode::stringValue(){
|
||||
return ftoa( value );
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
// String constant //
|
||||
/////////////////////
|
||||
StringConstNode::StringConstNode( const string &s ):value(s){
|
||||
sem_type=Type::string_type;
|
||||
}
|
||||
|
||||
TNode *StringConstNode::translate( Codegen *g ){
|
||||
string lab=genLabel();
|
||||
g->s_data( value,lab );
|
||||
return call( "__bbStrConst",global( lab ) );
|
||||
}
|
||||
|
||||
int StringConstNode::intValue(){
|
||||
return atoi( value );
|
||||
}
|
||||
|
||||
float StringConstNode::floatValue(){
|
||||
return (float)atof( value );
|
||||
}
|
||||
|
||||
string StringConstNode::stringValue(){
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Unary operator //
|
||||
////////////////////
|
||||
ExprNode *UniExprNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
sem_type=expr->sem_type;
|
||||
if( sem_type!=Type::int_type && sem_type!=Type::float_type ) ex( "Illegal operator for type" );
|
||||
if( ConstNode *c=expr->constNode() ){
|
||||
ExprNode *e;
|
||||
if( sem_type==Type::int_type ){
|
||||
switch( op ){
|
||||
case '+':e=d_new IntConstNode( +c->intValue() );break;
|
||||
case '-':e=d_new IntConstNode( -c->intValue() );break;
|
||||
case ABS:e=d_new IntConstNode( c->intValue()>=0 ? c->intValue() : -c->intValue() );break;
|
||||
case SGN:e=d_new IntConstNode( c->intValue()>0 ? 1 : (c->intValue()<0 ? -1 : 0) );break;
|
||||
}
|
||||
}else{
|
||||
switch( op ){
|
||||
case '+':e=d_new FloatConstNode( +c->floatValue() );break;
|
||||
case '-':e=d_new FloatConstNode( -c->floatValue() );break;
|
||||
case ABS:e=d_new FloatConstNode( c->floatValue()>=0 ? c->floatValue() : -c->floatValue() );break;
|
||||
case SGN:e=d_new FloatConstNode( c->floatValue()>0 ? 1 : (c->floatValue()<0 ? -1 : 0) );break;
|
||||
}
|
||||
}
|
||||
delete this;
|
||||
return e;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *UniExprNode::translate( Codegen *g ){
|
||||
int n=0;
|
||||
TNode *l=expr->translate( g );
|
||||
if( sem_type==Type::int_type ){
|
||||
switch( op ){
|
||||
case '+':return l;
|
||||
case '-':n=IR_NEG;break;
|
||||
case ABS:return call( "__bbAbs",l );
|
||||
case SGN:return call( "__bbSgn",l );
|
||||
}
|
||||
}else{
|
||||
switch( op ){
|
||||
case '+':return l;
|
||||
case '-':n=IR_FNEG;break;
|
||||
case ABS:return fcall( "__bbFAbs",l );
|
||||
case SGN:return fcall( "__bbFSgn",l );
|
||||
}
|
||||
}
|
||||
return d_new TNode( n,l,0 );
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// boolean expression - accepts ints, returns ints //
|
||||
/////////////////////////////////////////////////////
|
||||
ExprNode *BinExprNode::semant( Environ *e ){
|
||||
lhs=lhs->semant(e);lhs=lhs->castTo( Type::int_type,e );
|
||||
rhs=rhs->semant(e);rhs=rhs->castTo( Type::int_type,e );
|
||||
ConstNode *lc=lhs->constNode(),*rc=rhs->constNode();
|
||||
if( lc && rc ){
|
||||
ExprNode *expr;
|
||||
switch( op ){
|
||||
case AND:expr=d_new IntConstNode( lc->intValue() & rc->intValue() );break;
|
||||
case OR: expr=d_new IntConstNode( lc->intValue() | rc->intValue() );break;
|
||||
case XOR:expr=d_new IntConstNode( lc->intValue() ^ rc->intValue() );break;
|
||||
case SHL:expr=d_new IntConstNode( lc->intValue()<< rc->intValue() );break;
|
||||
case SHR:expr=d_new IntConstNode( (unsigned)lc->intValue()>>rc->intValue() );break;
|
||||
case SAR:expr=d_new IntConstNode( lc->intValue()>> rc->intValue() );break;
|
||||
}
|
||||
delete this;
|
||||
return expr;
|
||||
}
|
||||
sem_type=Type::int_type;
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *BinExprNode::translate( Codegen *g ){
|
||||
TNode *l=lhs->translate( g );
|
||||
TNode *r=rhs->translate( g );
|
||||
int n=0;
|
||||
switch( op ){
|
||||
case AND:n=IR_AND;break;case OR:n=IR_OR;break;case XOR:n=IR_XOR;break;
|
||||
case SHL:n=IR_SHL;break;case SHR:n=IR_SHR;break;case SAR:n=IR_SAR;break;
|
||||
}
|
||||
return d_new TNode( n,l,r );
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// arithmetic expression //
|
||||
///////////////////////////
|
||||
ExprNode *ArithExprNode::semant( Environ *e ){
|
||||
lhs=lhs->semant(e);
|
||||
rhs=rhs->semant(e);
|
||||
if( lhs->sem_type->structType() || rhs->sem_type->structType() ){
|
||||
ex( "Arithmetic operator cannot be applied to custom type objects" );
|
||||
}
|
||||
if( lhs->sem_type==Type::string_type || rhs->sem_type==Type::string_type ){
|
||||
//one side is a string - only + operator...
|
||||
if( op!='+' ) ex( "Operator cannot be applied to strings" );
|
||||
sem_type=Type::string_type;
|
||||
}else if( op=='^' || lhs->sem_type==Type::float_type || rhs->sem_type==Type::float_type ){
|
||||
//It's ^, or one side is a float
|
||||
sem_type=Type::float_type;
|
||||
}else{
|
||||
//must be 2 ints
|
||||
sem_type=Type::int_type;
|
||||
}
|
||||
lhs=lhs->castTo( sem_type,e );
|
||||
rhs=rhs->castTo( sem_type,e );
|
||||
ConstNode *lc=lhs->constNode(),*rc=rhs->constNode();
|
||||
if( rc && (op=='/' || op==MOD) ){
|
||||
if( (sem_type==Type::int_type && !rc->intValue()) || (sem_type==Type::float_type && !rc->floatValue()) ){
|
||||
ex( "Division by zero" );
|
||||
}
|
||||
}
|
||||
if( lc && rc ){
|
||||
ExprNode *expr;
|
||||
if( sem_type==Type::string_type ){
|
||||
expr=d_new StringConstNode( lc->stringValue()+rc->stringValue() );
|
||||
}else if( sem_type==Type::int_type ){
|
||||
switch( op ){
|
||||
case '+':expr=d_new IntConstNode( lc->intValue()+rc->intValue() );break;
|
||||
case '-':expr=d_new IntConstNode( lc->intValue()-rc->intValue() );break;
|
||||
case '*':expr=d_new IntConstNode( lc->intValue()*rc->intValue() );break;
|
||||
case '/':expr=d_new IntConstNode( lc->intValue()/rc->intValue() );break;
|
||||
case MOD:expr=d_new IntConstNode( lc->intValue()%rc->intValue() );break;
|
||||
}
|
||||
}else{
|
||||
switch( op ){
|
||||
case '+':expr=d_new FloatConstNode( lc->floatValue()+rc->floatValue() );break;
|
||||
case '-':expr=d_new FloatConstNode( lc->floatValue()-rc->floatValue() );break;
|
||||
case '*':expr=d_new FloatConstNode( lc->floatValue()*rc->floatValue() );break;
|
||||
case '/':expr=d_new FloatConstNode( lc->floatValue()/rc->floatValue() );break;
|
||||
case MOD:expr=d_new FloatConstNode( fmod( lc->floatValue(),rc->floatValue() ) );break;
|
||||
case '^':expr=d_new FloatConstNode( pow( lc->floatValue(),rc->floatValue() ) );break;
|
||||
}
|
||||
}
|
||||
delete this;
|
||||
return expr;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *ArithExprNode::translate( Codegen *g ){
|
||||
TNode *l=lhs->translate( g );
|
||||
TNode *r=rhs->translate( g );
|
||||
if( sem_type==Type::string_type ){
|
||||
return call( "__bbStrConcat",l,r );
|
||||
}
|
||||
int n=0;
|
||||
if( sem_type==Type::int_type ){
|
||||
switch( op ){
|
||||
case '+':n=IR_ADD;break;case '-':n=IR_SUB;break;
|
||||
case '*':n=IR_MUL;break;case '/':n=IR_DIV;break;
|
||||
case MOD:return call( "__bbMod",l,r );
|
||||
}
|
||||
}else{
|
||||
switch( op ){
|
||||
case '+':n=IR_FADD;break;case '-':n=IR_FSUB;break;
|
||||
case '*':n=IR_FMUL;break;case '/':n=IR_FDIV;break;
|
||||
case MOD:return fcall( "__bbFMod",l,r );
|
||||
case '^':return fcall( "__bbFPow",l,r );
|
||||
}
|
||||
}
|
||||
return d_new TNode( n,l,r );
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// relation expression //
|
||||
/////////////////////////
|
||||
ExprNode *RelExprNode::semant( Environ *e ){
|
||||
lhs=lhs->semant(e);
|
||||
rhs=rhs->semant(e);
|
||||
if( lhs->sem_type->structType() || rhs->sem_type->structType() ){
|
||||
if( op!='=' && op!=NE ) ex( "Illegal operator for custom type objects" );
|
||||
opType=lhs->sem_type!=Type::null_type ? lhs->sem_type : rhs->sem_type;
|
||||
}else if( lhs->sem_type==Type::string_type || rhs->sem_type==Type::string_type ){
|
||||
opType=Type::string_type;
|
||||
}else if( lhs->sem_type==Type::float_type || rhs->sem_type==Type::float_type ){
|
||||
opType=Type::float_type;
|
||||
}else{
|
||||
opType=Type::int_type;
|
||||
}
|
||||
sem_type=Type::int_type;
|
||||
lhs=lhs->castTo( opType,e );
|
||||
rhs=rhs->castTo( opType,e );
|
||||
ConstNode *lc=lhs->constNode(),*rc=rhs->constNode();
|
||||
if( lc && rc ){
|
||||
ExprNode *expr;
|
||||
if( opType==Type::string_type ){
|
||||
switch( op ){
|
||||
case '<':expr=d_new IntConstNode( lc->stringValue()< rc->stringValue() );break;
|
||||
case '=':expr=d_new IntConstNode( lc->stringValue()==rc->stringValue() );break;
|
||||
case '>':expr=d_new IntConstNode( lc->stringValue()> rc->stringValue() );break;
|
||||
case LE: expr=d_new IntConstNode( lc->stringValue()<=rc->stringValue() );break;
|
||||
case NE: expr=d_new IntConstNode( lc->stringValue()!=rc->stringValue() );break;
|
||||
case GE: expr=d_new IntConstNode( lc->stringValue()>=rc->stringValue() );break;
|
||||
}
|
||||
}else if( opType==Type::float_type ){
|
||||
switch( op ){
|
||||
case '<':expr=d_new IntConstNode( lc->floatValue()< rc->floatValue() );break;
|
||||
case '=':expr=d_new IntConstNode( lc->floatValue()==rc->floatValue() );break;
|
||||
case '>':expr=d_new IntConstNode( lc->floatValue()> rc->floatValue() );break;
|
||||
case LE: expr=d_new IntConstNode( lc->floatValue()<=rc->floatValue() );break;
|
||||
case NE: expr=d_new IntConstNode( lc->floatValue()!=rc->floatValue() );break;
|
||||
case GE: expr=d_new IntConstNode( lc->floatValue()>=rc->floatValue() );break;
|
||||
}
|
||||
}else{
|
||||
switch( op ){
|
||||
case '<':expr=d_new IntConstNode( lc->intValue()< rc->intValue() );break;
|
||||
case '=':expr=d_new IntConstNode( lc->intValue()==rc->intValue() );break;
|
||||
case '>':expr=d_new IntConstNode( lc->intValue()> rc->intValue() );break;
|
||||
case LE: expr=d_new IntConstNode( lc->intValue()<=rc->intValue() );break;
|
||||
case NE: expr=d_new IntConstNode( lc->intValue()!=rc->intValue() );break;
|
||||
case GE: expr=d_new IntConstNode( lc->intValue()>=rc->intValue() );break;
|
||||
}
|
||||
}
|
||||
delete this;
|
||||
return expr;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *RelExprNode::translate( Codegen *g ){
|
||||
TNode *l=lhs->translate( g );
|
||||
TNode *r=rhs->translate( g );
|
||||
return compare( op,l,r,opType );
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// New expression //
|
||||
////////////////////
|
||||
ExprNode *NewNode::semant( Environ *e ){
|
||||
sem_type=e->findType( ident );
|
||||
if( !sem_type ) ex( "custom type name not found" );
|
||||
if( sem_type->structType()==0 ) ex( "type is not a custom type" );
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *NewNode::translate( Codegen *g ){
|
||||
return call( "__bbObjNew",global( "_t"+ident ) );
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// First of class //
|
||||
////////////////////
|
||||
ExprNode *FirstNode::semant( Environ *e ){
|
||||
sem_type=e->findType( ident );
|
||||
if( !sem_type ) ex( "custom type name name not found" );
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *FirstNode::translate( Codegen *g ){
|
||||
return call( "__bbObjFirst",global( "_t"+ident ) );
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// Last of class //
|
||||
///////////////////
|
||||
ExprNode *LastNode::semant( Environ *e ){
|
||||
sem_type=e->findType( ident );
|
||||
if( !sem_type ) ex( "custom type name not found" );
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *LastNode::translate( Codegen *g ){
|
||||
return call( "__bbObjLast",global( "_t"+ident ) );
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Next of object //
|
||||
////////////////////
|
||||
ExprNode *AfterNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
if( expr->sem_type==Type::null_type ) ex( "'After' cannot be used on 'Null'" );
|
||||
if( expr->sem_type->structType()==0 ) ex( "'After' must be used with a custom type object" );
|
||||
sem_type=expr->sem_type;
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *AfterNode::translate( Codegen *g ){
|
||||
TNode *t=expr->translate( g );
|
||||
if( g->debug ) t=jumpf( t,"__bbNullObjEx" );
|
||||
return call( "__bbObjNext",t );
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Prev of object //
|
||||
////////////////////
|
||||
ExprNode *BeforeNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
if( expr->sem_type==Type::null_type ) ex( "'Before' cannot be used with 'Null'" );
|
||||
if( expr->sem_type->structType()==0 ) ex( "'Before' must be used with a custom type object" );
|
||||
sem_type=expr->sem_type;
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *BeforeNode::translate( Codegen *g ){
|
||||
TNode *t=expr->translate( g );
|
||||
if( g->debug ) t=jumpf( t,"__bbNullObjEx" );
|
||||
return call( "__bbObjPrev",t );
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// Null object //
|
||||
/////////////////
|
||||
ExprNode *NullNode::semant( Environ *e ){
|
||||
sem_type=Type::null_type;
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *NullNode::translate( Codegen *g ){
|
||||
return d_new TNode( IR_CONST,0,0,0 );
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// Object cast //
|
||||
/////////////////
|
||||
ExprNode *ObjectCastNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
expr=expr->castTo( Type::int_type,e );
|
||||
sem_type=e->findType( type_ident );
|
||||
if( !sem_type ) ex( "custom type name not found" );
|
||||
if( !sem_type->structType() ) ex( "type is not a custom type" );
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *ObjectCastNode::translate( Codegen *g ){
|
||||
TNode *t=expr->translate( g );
|
||||
t=call( "__bbObjFromHandle",t,global( "_t"+sem_type->structType()->ident ) );
|
||||
return t;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// Object Handle //
|
||||
///////////////////
|
||||
ExprNode *ObjectHandleNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
if( !expr->sem_type->structType() ) ex( "'ObjectHandle' must be used with an object" );
|
||||
sem_type=Type::int_type;
|
||||
return this;
|
||||
}
|
||||
|
||||
TNode *ObjectHandleNode::translate( Codegen *g ){
|
||||
TNode *t=expr->translate( g );
|
||||
return call( "__bbObjToHandle",t );
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
|
||||
#ifndef EXPRNODE_H
|
||||
#define EXPRNODE_H
|
||||
|
||||
#include "node.h"
|
||||
|
||||
struct ConstNode; //is constant int,float or string
|
||||
|
||||
struct ExprNode : public Node{
|
||||
Type *sem_type;
|
||||
ExprNode():sem_type(0){}
|
||||
ExprNode( Type *t ):sem_type( t ){}
|
||||
|
||||
ExprNode *castTo( Type *ty,Environ *e );
|
||||
ExprNode *semant( Environ *e,Type *ty );
|
||||
|
||||
virtual ExprNode *semant( Environ *e )=0;
|
||||
virtual TNode *translate( Codegen *g )=0;
|
||||
virtual ConstNode *constNode(){ return 0; }
|
||||
};
|
||||
|
||||
struct ExprSeqNode : public Node{
|
||||
vector<ExprNode*> exprs;
|
||||
~ExprSeqNode(){ for( ;exprs.size();exprs.pop_back() ) delete exprs.back(); }
|
||||
void push_back( ExprNode *e ){ exprs.push_back( e ); }
|
||||
int size(){ return exprs.size(); }
|
||||
void semant( Environ *e );
|
||||
TNode *translate( Codegen *g,bool userlib );
|
||||
void castTo( DeclSeq *ds,Environ *e,bool userlib );
|
||||
void castTo( Type *t,Environ *e );
|
||||
};
|
||||
|
||||
#include "varnode.h"
|
||||
|
||||
struct CastNode : public ExprNode{
|
||||
ExprNode *expr;
|
||||
Type *type;
|
||||
CastNode( ExprNode *ex,Type *ty ):expr( ex ),type( ty ){}
|
||||
~CastNode(){ delete expr; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct CallNode : public ExprNode{
|
||||
string ident,tag;
|
||||
ExprSeqNode *exprs;
|
||||
Decl *sem_decl;
|
||||
CallNode( const string &i,const string &t,ExprSeqNode *e ):ident(i),tag(t),exprs(e){}
|
||||
~CallNode(){ delete exprs; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct VarExprNode : public ExprNode{
|
||||
VarNode *var;
|
||||
VarExprNode( VarNode *v ):var(v){}
|
||||
~VarExprNode(){ delete var; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ConstNode : public ExprNode{
|
||||
ExprNode *semant( Environ *e ){ return this; }
|
||||
ConstNode *constNode(){ return this; }
|
||||
virtual int intValue()=0;
|
||||
virtual float floatValue()=0;
|
||||
virtual string stringValue()=0;
|
||||
};
|
||||
|
||||
struct IntConstNode : public ConstNode{
|
||||
int value;
|
||||
IntConstNode( int n );
|
||||
TNode *translate( Codegen *g );
|
||||
int intValue();
|
||||
float floatValue();
|
||||
string stringValue();
|
||||
};
|
||||
|
||||
struct FloatConstNode : public ConstNode{
|
||||
float value;
|
||||
FloatConstNode( float f );
|
||||
TNode *translate( Codegen *g );
|
||||
int intValue();
|
||||
float floatValue();
|
||||
string stringValue();
|
||||
};
|
||||
|
||||
struct StringConstNode : public ConstNode{
|
||||
string value;
|
||||
StringConstNode( const string &s );
|
||||
TNode *translate( Codegen *g );
|
||||
int intValue();
|
||||
float floatValue();
|
||||
string stringValue();
|
||||
};
|
||||
|
||||
struct UniExprNode : public ExprNode{
|
||||
int op;ExprNode *expr;
|
||||
UniExprNode( int op,ExprNode *expr ):op( op ),expr( expr ){}
|
||||
~UniExprNode(){ delete expr; }
|
||||
ExprNode *constize();
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
// and, or, eor, lsl, lsr, asr
|
||||
struct BinExprNode : public ExprNode{
|
||||
int op;ExprNode *lhs,*rhs;
|
||||
BinExprNode( int op,ExprNode *lhs,ExprNode *rhs ):op( op ),lhs( lhs ),rhs( rhs ){}
|
||||
~BinExprNode(){ delete lhs;delete rhs; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
// *,/,Mod,+,-
|
||||
struct ArithExprNode : public ExprNode{
|
||||
int op;ExprNode *lhs,*rhs;
|
||||
ArithExprNode( int op,ExprNode *lhs,ExprNode *rhs ):op( op ),lhs( lhs ),rhs( rhs ){}
|
||||
~ArithExprNode(){ delete lhs;delete rhs; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
//<,=,>,<=,<>,>=
|
||||
struct RelExprNode : public ExprNode{
|
||||
int op;ExprNode *lhs,*rhs;
|
||||
Type *opType;
|
||||
RelExprNode( int op,ExprNode *lhs,ExprNode *rhs ):op( op ),lhs( lhs ),rhs( rhs ){}
|
||||
~RelExprNode(){ delete lhs;delete rhs; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct NewNode : public ExprNode{
|
||||
string ident;
|
||||
NewNode( const string &i ):ident(i){}
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct FirstNode : public ExprNode{
|
||||
string ident;
|
||||
FirstNode( const string &i ):ident(i){}
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct LastNode : public ExprNode{
|
||||
string ident;
|
||||
LastNode( const string &i ):ident(i){}
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct AfterNode : public ExprNode{
|
||||
ExprNode *expr;
|
||||
AfterNode( ExprNode *e ):expr(e){}
|
||||
~AfterNode(){ delete expr; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct BeforeNode : public ExprNode{
|
||||
ExprNode *expr;
|
||||
BeforeNode( ExprNode *e ):expr(e){}
|
||||
~BeforeNode(){ delete expr; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct NullNode : public ExprNode{
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ObjectCastNode : public ExprNode{
|
||||
ExprNode *expr;
|
||||
string type_ident;
|
||||
ObjectCastNode( ExprNode *e,const string &t ):expr(e),type_ident(t){}
|
||||
~ObjectCastNode(){ delete expr; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ObjectHandleNode : public ExprNode{
|
||||
ExprNode *expr;
|
||||
ObjectHandleNode( ExprNode *e ):expr(e){}
|
||||
~ObjectHandleNode(){ delete expr; }
|
||||
ExprNode *semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
Intermediate representation of program:
|
||||
|
||||
Data...
|
||||
|
||||
LABEL( sconst ) ;insert an ASM label
|
||||
INT( iconst ) ;insert int constant
|
||||
FLOAT( fconst ) ;insert float constant
|
||||
STRING( sconst ) ;insert string constant
|
||||
|
||||
Code...
|
||||
|
||||
Statements only:
|
||||
|
||||
ENTER( iconst ) ;enter func with iconst locals
|
||||
LEAVE( iconst ) ;leave func with iconst locals
|
||||
JUMP( sconst ) ;jump to label sconst
|
||||
JUMPT( l,sconst ) ;eval expr-l, if !=0 jump to label sconst
|
||||
JUMPF( r,sconst ) ;eval expr-r, if ==0 jump to label sconst
|
||||
RETURN( l,sconst ) ;eval expr-l into return reg and jump to label sconst
|
||||
STORE( l,r ) ;eval expr-r and store it in expr-l
|
||||
|
||||
Stmts or expressions:
|
||||
|
||||
CALL( l,r ) ;eval expr-r, push it and call expr-l
|
||||
ARGS( l,r ) ;eval expr-r, push it, eval expr-l
|
||||
FRAME() ;copy of frame pointer
|
||||
GLOBAL( sconst ) ;address of label sconst
|
||||
LOAD( l ) ;integer load
|
||||
NEG( l ),NOT( l ).. ;integer uniops
|
||||
ADD( l,r ),SUB( l,r ).. ;integer binops
|
||||
CONST( iconst ) ;integer constant
|
||||
CAST( l ) ;cast float expr-l to int
|
||||
FLOAD( l ) ;float load
|
||||
FNEG( l ),FNOT( l ).. ;float uniops
|
||||
FADD( l,r ),FSUB( l,r ).;float binops
|
||||
FCONST( fconst ) ;float constant
|
||||
FCAST( l ) ;cast int expr-l to float
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
#ifndef LABEL_H
|
||||
#define LABEL_H
|
||||
|
||||
struct Label{
|
||||
string name; //name of label
|
||||
int def,ref; //pos of defn and goto/restore src
|
||||
int data_sz; //size of data at this label.
|
||||
|
||||
Label( const string &n,int d,int r,int sz ):name(n),def(d),ref(r),data_sz(sz){}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,284 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "nodes.h"
|
||||
|
||||
set<string> Node::usedfuncs;
|
||||
|
||||
///////////////////////////////
|
||||
// generic exception thrower //
|
||||
///////////////////////////////
|
||||
void Node::ex(){
|
||||
ex( "INTERNAL COMPILER ERROR" );
|
||||
}
|
||||
|
||||
void Node::ex( const string &e ){
|
||||
throw Ex( e,-1,"" );
|
||||
}
|
||||
|
||||
void Node::ex( const string &e,int pos ){
|
||||
throw Ex( e,pos,"" );
|
||||
}
|
||||
|
||||
void Node::ex( const string &e,int pos,const string &f ){
|
||||
throw Ex( e,pos,f );
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// Generate a local variable //
|
||||
///////////////////////////////
|
||||
VarNode *Node::genLocal( Environ *e,Type *ty ){
|
||||
string t=genLabel();
|
||||
Decl *d=e->decls->insertDecl( t,ty,DECL_LOCAL );
|
||||
return d_new DeclVarNode( d );
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// if type is const, return const value else 0 //
|
||||
/////////////////////////////////////////////////
|
||||
ConstNode *Node::constValue( Type *ty ){
|
||||
ConstType *c=ty->constType();
|
||||
if( !c ) return 0;
|
||||
ty=c->valueType;
|
||||
if( ty==Type::int_type ) return d_new IntConstNode( c->intValue );
|
||||
if( ty==Type::float_type ) return d_new FloatConstNode( c->floatValue );
|
||||
return d_new StringConstNode( c->stringValue );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// work out var offsets - return size of local frame //
|
||||
///////////////////////////////////////////////////////
|
||||
int Node::enumVars( Environ *e ){
|
||||
//calc offsets
|
||||
int p_size=0,l_size=0;
|
||||
for( int k=0;k<e->decls->size();++k ){
|
||||
Decl *d=e->decls->decls[k];
|
||||
if( d->kind & DECL_PARAM ){
|
||||
d->offset=p_size+20;
|
||||
p_size+=4;
|
||||
}else if( d->kind & DECL_LOCAL ){
|
||||
d->offset=-4-l_size;
|
||||
l_size+=4;
|
||||
}
|
||||
}
|
||||
return l_size;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// initialize all vars to 0 //
|
||||
//////////////////////////////
|
||||
TNode *Node::createVars( Environ *e ){
|
||||
int k;
|
||||
TNode *t=0;
|
||||
//initialize locals
|
||||
for( k=0;k<e->decls->size();++k ){
|
||||
Decl *d=e->decls->decls[k];
|
||||
if( d->kind!=DECL_LOCAL ) continue;
|
||||
if( d->type->vectorType() ) continue;
|
||||
if( !t ) t=d_new TNode( IR_CONST,0,0,0 );
|
||||
TNode *p=d_new TNode( IR_LOCAL,0,0,d->offset );
|
||||
p=d_new TNode( IR_MEM,p,0 );
|
||||
t=d_new TNode( IR_MOVE,t,p );
|
||||
}
|
||||
//initialize vectors
|
||||
for( k=0;k<e->decls->size();++k ){
|
||||
Decl *d=e->decls->decls[k];
|
||||
if( d->kind==DECL_PARAM ) continue;
|
||||
VectorType *v=d->type->vectorType();
|
||||
if( !v ) continue;
|
||||
TNode *p=call( "__bbVecAlloc",global( v->label ) );
|
||||
TNode *m=d->kind==DECL_GLOBAL ? global( "_v"+d->name ) : local( d->offset );
|
||||
p=move( p,mem( m ) );
|
||||
if( t ) t=seq( t,p );
|
||||
else t=p;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// release local vars //
|
||||
////////////////////////
|
||||
TNode *Node::deleteVars( Environ *e ){
|
||||
TNode *t=0,*l=0,*p,*p1,*p2;
|
||||
for( int k=0;k<e->decls->size();++k ){
|
||||
Decl *d=e->decls->decls[k];
|
||||
Type *type=d->type;
|
||||
string func;
|
||||
if( type==Type::string_type ){
|
||||
if( d->kind==DECL_LOCAL || d->kind==DECL_PARAM ){
|
||||
func="__bbStrRelease";
|
||||
p1=mem( local( d->offset ) );
|
||||
p2=0;
|
||||
}
|
||||
}else if( type->structType() ){
|
||||
if( d->kind==DECL_LOCAL ){
|
||||
func="__bbObjRelease";
|
||||
p1=mem( local( d->offset ) );
|
||||
p2=0;
|
||||
}
|
||||
}else if( VectorType *v=type->vectorType() ){
|
||||
if( d->kind==DECL_LOCAL ){
|
||||
func="__bbVecFree";
|
||||
p1=mem( local( d->offset ) );
|
||||
p2=global( v->label );
|
||||
}
|
||||
}
|
||||
if( !func.size() ) continue;
|
||||
p=d_new TNode( IR_SEQ,call( func,p1,p2 ),0 );
|
||||
(l ? l->r : t)=p;
|
||||
l=p;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// compare 2 translated operands - return 1 if true, else 0 //
|
||||
//////////////////////////////////////////////////////////////
|
||||
TNode *Node::compare( int op,TNode *l,TNode *r,Type *ty ){
|
||||
int n=0;
|
||||
if( ty==Type::float_type ){
|
||||
switch( op ){
|
||||
case '=':n=IR_FSETEQ;break;case NE :n=IR_FSETNE;break;
|
||||
case '<':n=IR_FSETLT;break;case '>':n=IR_FSETGT;break;
|
||||
case LE :n=IR_FSETLE;break;case GE :n=IR_FSETGE;break;
|
||||
}
|
||||
}else{
|
||||
switch( op ){
|
||||
case '=':n=IR_SETEQ;break;case NE :n=IR_SETNE;break;
|
||||
case '<':n=IR_SETLT;break;case '>':n=IR_SETGT;break;
|
||||
case LE :n=IR_SETLE;break;case GE :n=IR_SETGE;break;
|
||||
}
|
||||
}
|
||||
if( ty==Type::string_type ){
|
||||
l=call( "__bbStrCompare",l,r );
|
||||
r=d_new TNode( IR_CONST,0,0,0 );
|
||||
}else if( ty->structType() ){
|
||||
l=call( "__bbObjCompare",l,r );
|
||||
r=d_new TNode( IR_CONST,0,0,0 );
|
||||
}
|
||||
return d_new TNode( n,l,r );
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
// calculate the type of a tag //
|
||||
/////////////////////////////////
|
||||
Type *Node::tagType( const string &tag,Environ *e ){
|
||||
Type *t;
|
||||
if( tag.size() ){
|
||||
t=e->findType( tag );
|
||||
if( !t ) ex( "Type \""+tag+"\" not found" );
|
||||
}else t=0;
|
||||
return t;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// Generate a fresh ASM label //
|
||||
////////////////////////////////
|
||||
string Node::genLabel(){
|
||||
static int cnt;
|
||||
return "_"+itoa( ++cnt & 0x7fffffff );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// create a stmt-type function call with int result //
|
||||
//////////////////////////////////////////////////////
|
||||
TNode *Node::call( const string &func,TNode *a0,TNode *a1,TNode *a2 ){
|
||||
int size=0;
|
||||
TNode *t=0;
|
||||
if( a0 ){
|
||||
t=move( a0,mem( arg(0) ) );
|
||||
size+=4;
|
||||
if( a1 ){
|
||||
t=seq( t,move( a1,mem( arg(4) ) ) );
|
||||
size+=4;
|
||||
if( a2 ){
|
||||
t=seq( t,move( a2,mem( arg(8) ) ) );
|
||||
size+=4;
|
||||
}
|
||||
}
|
||||
}
|
||||
TNode *l=d_new TNode( IR_GLOBAL,0,0,func );
|
||||
return d_new TNode( IR_CALL,l,t,size );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// create a stmt-type function call with float result //
|
||||
////////////////////////////////////////////////////////
|
||||
TNode *Node::fcall( const string &func,TNode *a0,TNode *a1,TNode *a2 ){
|
||||
int size=0;
|
||||
TNode *t=0;
|
||||
if( a0 ){
|
||||
t=move( a0,mem( arg(0) ) );
|
||||
size+=4;
|
||||
if( a1 ){
|
||||
t=seq( t,move( a1,mem( arg(4) ) ) );
|
||||
size+=4;
|
||||
if( a2 ){
|
||||
t=seq( t,move( a2,mem( arg(8) ) ) );
|
||||
size+=4;
|
||||
}
|
||||
}
|
||||
}
|
||||
TNode *l=d_new TNode( IR_GLOBAL,0,0,func );
|
||||
return d_new TNode( IR_FCALL,l,t,size );
|
||||
}
|
||||
|
||||
TNode *Node::seq( TNode *l,TNode *r ){
|
||||
return d_new TNode( IR_SEQ,l,r );
|
||||
}
|
||||
|
||||
TNode *Node::move( TNode *src,TNode *dest ){
|
||||
return d_new TNode( IR_MOVE,src,dest );
|
||||
}
|
||||
|
||||
TNode *Node::global( const string &s ){
|
||||
return d_new TNode( IR_GLOBAL,0,0,s );
|
||||
}
|
||||
|
||||
TNode *Node::local( int offset ){
|
||||
return d_new TNode( IR_LOCAL,0,0,offset );
|
||||
}
|
||||
|
||||
TNode *Node::arg( int offset ){
|
||||
return d_new TNode( IR_ARG,0,0,offset );
|
||||
}
|
||||
|
||||
TNode *Node::mem( TNode *ref ){
|
||||
return d_new TNode( IR_MEM,ref,0 );
|
||||
}
|
||||
|
||||
TNode *Node::add( TNode *l,TNode *r ){
|
||||
return d_new TNode( IR_ADD,l,r );
|
||||
}
|
||||
|
||||
TNode *Node::mul( TNode *l,TNode *r ){
|
||||
return d_new TNode( IR_MUL,l,r );
|
||||
}
|
||||
|
||||
TNode *Node::iconst( int n ){
|
||||
return d_new TNode( IR_CONST,0,0,n );
|
||||
}
|
||||
|
||||
TNode *Node::ret(){
|
||||
return d_new TNode( IR_RET,0,0 );
|
||||
}
|
||||
|
||||
TNode *Node::jsr( const string &s ){
|
||||
return d_new TNode( IR_JSR,0,0,s );
|
||||
}
|
||||
|
||||
TNode *Node::jump( const string &s ){
|
||||
return d_new TNode( IR_JUMP,0,0,s );
|
||||
}
|
||||
|
||||
TNode *Node::jumpt( TNode *expr,const string &s ){
|
||||
return d_new TNode( IR_JUMPT,expr,0,s );
|
||||
}
|
||||
|
||||
TNode *Node::jumpf( TNode *expr,const string &s ){
|
||||
return d_new TNode( IR_JUMPF,expr,0,s );
|
||||
}
|
||||
|
||||
TNode *Node::jumpge( TNode *l,TNode *r,const string &s ){
|
||||
return d_new TNode( IR_JUMPGE,l,r,s );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
#ifndef NODE_H
|
||||
#define NODE_H
|
||||
|
||||
#include "ex.h"
|
||||
#include "toker.h"
|
||||
#include "environ.h"
|
||||
#include "codegen.h"
|
||||
|
||||
struct VarNode;
|
||||
struct ConstNode;
|
||||
|
||||
struct Node{
|
||||
virtual ~Node(){}
|
||||
|
||||
//used user funcs...
|
||||
static set<string> usedfuncs;
|
||||
|
||||
//helper funcs
|
||||
static void ex();
|
||||
static void ex( const string &e );
|
||||
static void ex( const string &e,int pos );
|
||||
static void ex( const string &e,int pos,const string &f );
|
||||
|
||||
static string genLabel();
|
||||
static VarNode *genLocal( Environ *e,Type *ty );
|
||||
|
||||
static TNode *compare( int op,TNode *l,TNode *r,Type *ty );
|
||||
static ConstNode *constValue( Type *ty );
|
||||
|
||||
static int enumVars( Environ *e );
|
||||
static Type *tagType( const string &s,Environ *e );
|
||||
|
||||
static TNode *createVars( Environ *e );
|
||||
static TNode *deleteVars( Environ *e );
|
||||
|
||||
static TNode *seq( TNode *l,TNode *r );
|
||||
static TNode *move( TNode *src,TNode *dest );
|
||||
static TNode *global( const string &s );
|
||||
static TNode *local( int offset );
|
||||
static TNode *arg( int offset );
|
||||
static TNode *mem( TNode *ref );
|
||||
static TNode *add( TNode *l,TNode *r );
|
||||
static TNode *mul( TNode *l,TNode *r );
|
||||
static TNode *iconst( int n );
|
||||
static TNode *ret();
|
||||
static TNode *jsr( const string &s );
|
||||
static TNode *jump( const string &s );
|
||||
static TNode *jumpt( TNode *cond,const string &s );
|
||||
static TNode *jumpf( TNode *cond,const string &s );
|
||||
static TNode *jumpge( TNode *l,TNode *r,const string &s );
|
||||
static TNode *call( const string &func,TNode *a0=0,TNode *a1=0,TNode *a2=0 );
|
||||
static TNode *fcall( const string &func,TNode *a0=0,TNode *a1=0,TNode *a2=0 );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
#ifndef NODES_H
|
||||
#define NODES_H
|
||||
|
||||
#include "exprnode.h"
|
||||
#include "stmtnode.h"
|
||||
#include "declnode.h"
|
||||
#include "prognode.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,757 @@
|
||||
|
||||
#include "std.h"
|
||||
#include <cstdlib>
|
||||
#include "parser.h"
|
||||
|
||||
#ifdef DEMO
|
||||
static const int TEXTLIMIT=16384;
|
||||
#else
|
||||
static const int TEXTLIMIT=1024*1024-1;
|
||||
#endif
|
||||
|
||||
enum{
|
||||
STMTS_PROG,STMTS_BLOCK,STMTS_LINE
|
||||
};
|
||||
|
||||
static bool isTerm( int c ){ return c==':' || c=='\n'; }
|
||||
|
||||
Parser::Parser( Toker &t ):toker(&t),main_toker(&t){
|
||||
}
|
||||
|
||||
ProgNode *Parser::parse( const string &main ){
|
||||
|
||||
incfile=main;
|
||||
|
||||
consts=d_new DeclSeqNode();
|
||||
structs=d_new DeclSeqNode();
|
||||
funcs=d_new DeclSeqNode();
|
||||
datas=d_new DeclSeqNode();
|
||||
StmtSeqNode *stmts=0;
|
||||
|
||||
try{
|
||||
stmts=parseStmtSeq( STMTS_PROG );
|
||||
if( toker->curr()!=EOF ) exp( "end-of-file" );
|
||||
}catch( Ex ){
|
||||
delete stmts;delete datas;delete funcs;delete structs;delete consts;
|
||||
throw;
|
||||
}
|
||||
|
||||
return d_new ProgNode( consts,structs,funcs,datas,stmts );
|
||||
}
|
||||
|
||||
void Parser::ex( const string &s ){
|
||||
throw Ex( s,toker->pos(),incfile );
|
||||
}
|
||||
|
||||
void Parser::exp( const string &s ){
|
||||
switch( toker->curr() ){
|
||||
case NEXT:ex( "'Next' without 'For'" );
|
||||
case WEND:ex( "'Wend' without 'While'" );
|
||||
case ELSE:case ELSEIF:ex( "'Else' without 'If'" );
|
||||
case ENDIF:ex( "'Endif' without 'If'" );
|
||||
case ENDFUNCTION:ex( "'End Function' without 'Function'" );
|
||||
case UNTIL:ex( "'Until' without 'Repeat'" );
|
||||
case FOREVER:ex( "'Forever' without 'Repeat'" );
|
||||
case CASE:ex( "'Case' without 'Select'" );
|
||||
case ENDSELECT:ex( "'End Select' without 'Select'" );
|
||||
}
|
||||
ex( "Expecting "+s );
|
||||
}
|
||||
|
||||
string Parser::parseIdent(){
|
||||
if( toker->curr()!=IDENT ) exp( "identifier" );
|
||||
string t=toker->text();
|
||||
toker->next();
|
||||
return t;
|
||||
}
|
||||
|
||||
void Parser::parseChar( int c ){
|
||||
if( toker->curr()!=c ) exp( string( "'" )+char(c)+string( "'" ) );
|
||||
toker->next();
|
||||
}
|
||||
|
||||
StmtSeqNode *Parser::parseStmtSeq( int scope ){
|
||||
a_ptr<StmtSeqNode> stmts( d_new StmtSeqNode( incfile ) );
|
||||
parseStmtSeq( stmts,scope );
|
||||
return stmts.release();
|
||||
}
|
||||
|
||||
void Parser::parseStmtSeq( StmtSeqNode *stmts,int scope ){
|
||||
|
||||
for(;;){
|
||||
while( toker->curr()==':' || (scope!=STMTS_LINE && toker->curr()=='\n') ) toker->next();
|
||||
StmtNode *result=0;
|
||||
|
||||
int pos=toker->pos();
|
||||
|
||||
#ifdef DEMO
|
||||
if( Toker::chars_toked>TEXTLIMIT ){
|
||||
ex( "Demo version source limit exceeded" );
|
||||
}
|
||||
#endif
|
||||
switch( toker->curr() ){
|
||||
case INCLUDE:
|
||||
{
|
||||
if( toker->next()!=STRINGCONST ) exp( "include filename" );
|
||||
string inc=toker->text();toker->next();
|
||||
inc=inc.substr( 1,inc.size()-2 );
|
||||
|
||||
//WIN32 KLUDGE//
|
||||
char buff[MAX_PATH],*p;
|
||||
if( GetFullPathName( inc.c_str(),MAX_PATH,buff,&p ) ) inc=buff;
|
||||
inc=tolower(inc);
|
||||
|
||||
if( included.find( inc )!=included.end() ) break;
|
||||
|
||||
ifstream i_stream( inc.c_str() );
|
||||
if( !i_stream.good() ) ex( "Unable to open include file" );
|
||||
|
||||
Toker i_toker( i_stream );
|
||||
|
||||
string t_inc=incfile;incfile=inc;
|
||||
Toker *t_toker=toker;toker=&i_toker;
|
||||
|
||||
included.insert( incfile );
|
||||
|
||||
a_ptr<StmtSeqNode> ss( parseStmtSeq( scope ) );
|
||||
if( toker->curr()!=EOF ) exp( "end-of-file" );
|
||||
|
||||
result=d_new IncludeNode( incfile,ss.release() );
|
||||
|
||||
toker=t_toker;
|
||||
incfile=t_inc;
|
||||
}
|
||||
break;
|
||||
case IDENT:
|
||||
{
|
||||
string ident=toker->text();
|
||||
toker->next();string tag=parseTypeTag();
|
||||
if( arrayDecls.find(ident)==arrayDecls.end()
|
||||
&& toker->curr()!='=' && toker->curr()!='\\' && toker->curr()!='[' ){
|
||||
//must be a function
|
||||
ExprSeqNode *exprs;
|
||||
if( toker->curr()=='(' ){
|
||||
//ugly lookahead for optional '()' around statement params
|
||||
int nest=1,k;
|
||||
for( k=1;;++k ){
|
||||
int c=toker->lookAhead( k );
|
||||
if( isTerm( c ) ) ex( "Mismatched brackets" );
|
||||
else if( c=='(' ) ++nest;
|
||||
else if( c==')' && !--nest ) break;
|
||||
}
|
||||
if( isTerm( toker->lookAhead( ++k ) ) ){
|
||||
toker->next();
|
||||
exprs=parseExprSeq();
|
||||
if( toker->curr()!=')' ) exp( "')'" );
|
||||
toker->next();
|
||||
}else exprs=parseExprSeq();
|
||||
}else exprs=parseExprSeq();
|
||||
CallNode *call=d_new CallNode( ident,tag,exprs );
|
||||
result=d_new ExprStmtNode( call );
|
||||
}else{
|
||||
//must be a var
|
||||
a_ptr<VarNode> var( parseVar( ident,tag ) );
|
||||
if( toker->curr()!='=' ) exp( "variable assignment" );
|
||||
toker->next();ExprNode *expr=parseExpr( false );
|
||||
result=d_new AssNode( var.release(),expr );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IF:
|
||||
{
|
||||
toker->next();result=parseIf();
|
||||
if( toker->curr()==ENDIF ) toker->next();
|
||||
}
|
||||
break;
|
||||
case WHILE:
|
||||
{
|
||||
toker->next();
|
||||
a_ptr<ExprNode> expr( parseExpr( false ) );
|
||||
a_ptr<StmtSeqNode> stmts( parseStmtSeq( STMTS_BLOCK ) );
|
||||
int pos=toker->pos();
|
||||
if( toker->curr()!=WEND ) exp( "'Wend'" );
|
||||
toker->next();
|
||||
result=d_new WhileNode( expr.release(),stmts.release(),pos );
|
||||
}
|
||||
break;
|
||||
case REPEAT:
|
||||
{
|
||||
toker->next();ExprNode *expr=0;
|
||||
a_ptr<StmtSeqNode> stmts( parseStmtSeq( STMTS_BLOCK ) );
|
||||
int curr=toker->curr();
|
||||
int pos=toker->pos();
|
||||
if( curr!=UNTIL && curr!=FOREVER ) exp( "'Until' or 'Forever'" );
|
||||
toker->next();if( curr==UNTIL ) expr=parseExpr( false );
|
||||
result=d_new RepeatNode( stmts.release(),expr,pos );
|
||||
}
|
||||
break;
|
||||
case SELECT:
|
||||
{
|
||||
toker->next();ExprNode *expr=parseExpr( false );
|
||||
a_ptr<SelectNode> selNode( d_new SelectNode( expr ) );
|
||||
for(;;){
|
||||
while( isTerm( toker->curr() ) ) toker->next();
|
||||
if( toker->curr()==CASE ){
|
||||
toker->next();
|
||||
a_ptr<ExprSeqNode> exprs( parseExprSeq() );
|
||||
if( !exprs->size() ) exp( "expression sequence" );
|
||||
a_ptr<StmtSeqNode> stmts( parseStmtSeq( STMTS_BLOCK ) );
|
||||
selNode->push_back( d_new CaseNode( exprs.release(),stmts.release() ) );
|
||||
continue;
|
||||
}else if( toker->curr()==DEFAULT ){
|
||||
toker->next();
|
||||
a_ptr<StmtSeqNode> stmts( parseStmtSeq( STMTS_BLOCK ) );
|
||||
if( toker->curr()!=ENDSELECT ) exp( "'End Select'" );
|
||||
selNode->defStmts=stmts.release();
|
||||
break;
|
||||
}else if( toker->curr()==ENDSELECT ){
|
||||
break;
|
||||
}
|
||||
exp( "'Case', 'Default' or 'End Select'" );
|
||||
}
|
||||
toker->next();
|
||||
result=selNode.release();
|
||||
}
|
||||
break;
|
||||
case FOR:
|
||||
{
|
||||
a_ptr<VarNode> var;
|
||||
a_ptr<StmtSeqNode> stmts;
|
||||
toker->next();var=parseVar();
|
||||
if( toker->curr()!='=' ) exp( "variable assignment" );
|
||||
if( toker->next()==EACH ){
|
||||
toker->next();
|
||||
string ident=parseIdent();
|
||||
stmts=parseStmtSeq( STMTS_BLOCK );
|
||||
int pos=toker->pos();
|
||||
if( toker->curr()!=NEXT ) exp( "'Next'" );
|
||||
toker->next();
|
||||
result=d_new ForEachNode( var.release(),ident,stmts.release(),pos );
|
||||
}else{
|
||||
a_ptr<ExprNode> from,to,step;
|
||||
from=parseExpr( false );
|
||||
if( toker->curr()!=TO ) exp( "'TO'" );
|
||||
toker->next();to=parseExpr( false );
|
||||
//step...
|
||||
if( toker->curr()==STEP ){
|
||||
toker->next();step=parseExpr( false );
|
||||
}else step=d_new IntConstNode( 1 );
|
||||
stmts=parseStmtSeq( STMTS_BLOCK );
|
||||
int pos=toker->pos();
|
||||
if( toker->curr()!=NEXT ) exp( "'Next'" );
|
||||
toker->next();
|
||||
result=d_new ForNode( var.release(),from.release(),to.release(),step.release(),stmts.release(),pos );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXIT:
|
||||
{
|
||||
toker->next();result=d_new ExitNode();
|
||||
}
|
||||
break;
|
||||
case GOTO:
|
||||
{
|
||||
toker->next();string t=parseIdent();result=d_new GotoNode( t );
|
||||
}
|
||||
break;
|
||||
case GOSUB:
|
||||
{
|
||||
toker->next();string t=parseIdent();result=d_new GosubNode( t );
|
||||
}
|
||||
break;
|
||||
case RETURN:
|
||||
{
|
||||
toker->next();result=d_new ReturnNode( parseExpr( true ) );
|
||||
}
|
||||
break;
|
||||
case BBDELETE:
|
||||
{
|
||||
if( toker->next()==EACH ){
|
||||
toker->next();string t=parseIdent();
|
||||
result=d_new DeleteEachNode( t );
|
||||
}else{
|
||||
ExprNode *expr=parseExpr( false );
|
||||
result=d_new DeleteNode( expr );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INSERT:
|
||||
{
|
||||
toker->next();
|
||||
a_ptr<ExprNode> expr1( parseExpr( false ) );
|
||||
if( toker->curr()!=BEFORE && toker->curr()!=AFTER ) exp( "'Before' or 'After'" );
|
||||
bool before=toker->curr()==BEFORE;toker->next();
|
||||
a_ptr<ExprNode> expr2( parseExpr( false ) );
|
||||
result=d_new InsertNode( expr1.release(),expr2.release(),before );
|
||||
}
|
||||
break;
|
||||
case READ:
|
||||
do{
|
||||
toker->next();VarNode *var=parseVar();
|
||||
StmtNode *stmt=d_new ReadNode( var );
|
||||
stmt->pos=pos;pos=toker->pos();
|
||||
stmts->push_back( stmt );
|
||||
}while( toker->curr()==',' );
|
||||
break;
|
||||
case RESTORE:
|
||||
if( toker->next()==IDENT ){
|
||||
result=d_new RestoreNode( toker->text() );toker->next();
|
||||
}else result=d_new RestoreNode( "" );
|
||||
break;
|
||||
case DATA:
|
||||
if( scope!=STMTS_PROG ) ex( "'Data' can only appear in main program" );
|
||||
do{
|
||||
toker->next();
|
||||
ExprNode *expr=parseExpr( false );
|
||||
datas->push_back( d_new DataDeclNode( expr ) );
|
||||
}while( toker->curr()==',' );
|
||||
break;
|
||||
case TYPE:
|
||||
if( scope!=STMTS_PROG ) ex( "'Type' can only appear in main program" );
|
||||
toker->next();structs->push_back( parseStructDecl() );
|
||||
break;
|
||||
case BBCONST:
|
||||
if( scope!=STMTS_PROG ) ex( "'Const' can only appear in main program" );
|
||||
do{
|
||||
toker->next();consts->push_back( parseVarDecl( DECL_GLOBAL,true ) );
|
||||
}while( toker->curr()==',' );
|
||||
break;
|
||||
case FUNCTION:
|
||||
if( scope!=STMTS_PROG ) ex( "'Function' can only appear in main program" );
|
||||
toker->next();funcs->push_back( parseFuncDecl() );
|
||||
break;
|
||||
case DIM:
|
||||
do{
|
||||
toker->next();
|
||||
StmtNode *stmt=parseArrayDecl();
|
||||
stmt->pos=pos;pos=toker->pos();
|
||||
stmts->push_back( stmt );
|
||||
}while( toker->curr()==',' );
|
||||
break;
|
||||
case LOCAL:
|
||||
do{
|
||||
toker->next();
|
||||
DeclNode *d=parseVarDecl( DECL_LOCAL,false );
|
||||
StmtNode *stmt=d_new DeclStmtNode( d );
|
||||
stmt->pos=pos;pos=toker->pos();
|
||||
stmts->push_back( stmt );
|
||||
}while( toker->curr()==',' );
|
||||
break;
|
||||
case GLOBAL:
|
||||
if( scope!=STMTS_PROG ) ex( "'Global' can only appear in main program" );
|
||||
do{
|
||||
toker->next();
|
||||
DeclNode *d=parseVarDecl( DECL_GLOBAL,false );
|
||||
StmtNode *stmt=d_new DeclStmtNode( d );
|
||||
stmt->pos=pos;pos=toker->pos();
|
||||
stmts->push_back( stmt );
|
||||
}while( toker->curr()==',' );
|
||||
break;
|
||||
case '.':
|
||||
{
|
||||
toker->next();string t=parseIdent();
|
||||
result=d_new LabelNode( t,datas->size() );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if( result ){
|
||||
result->pos=pos;
|
||||
stmts->push_back( result );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string Parser::parseTypeTag(){
|
||||
switch( toker->curr() ){
|
||||
case '%':toker->next();return "%";
|
||||
case '#':toker->next();return "#";
|
||||
case '$':toker->next();return "$";
|
||||
case '.':toker->next();return parseIdent();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
VarNode *Parser::parseVar(){
|
||||
string ident=parseIdent();
|
||||
string tag=parseTypeTag();
|
||||
return parseVar( ident,tag );
|
||||
}
|
||||
|
||||
VarNode *Parser::parseVar( const string &ident,const string &tag ){
|
||||
a_ptr<VarNode> var;
|
||||
if( toker->curr()=='(' ){
|
||||
toker->next();
|
||||
a_ptr<ExprSeqNode> exprs( parseExprSeq() );
|
||||
if( toker->curr()!=')' ) exp( "')'" );
|
||||
toker->next();
|
||||
var=d_new ArrayVarNode( ident,tag,exprs.release() );
|
||||
}else var=d_new IdentVarNode( ident,tag );
|
||||
|
||||
for(;;){
|
||||
if( toker->curr()=='\\' ){
|
||||
toker->next();
|
||||
string ident=parseIdent();
|
||||
string tag=parseTypeTag();
|
||||
ExprNode *expr=d_new VarExprNode( var.release() );
|
||||
var=d_new FieldVarNode( expr,ident,tag );
|
||||
}else if( toker->curr()=='[' ){
|
||||
toker->next();
|
||||
a_ptr<ExprSeqNode> exprs( parseExprSeq() );
|
||||
if( exprs->exprs.size()!=1 || toker->curr()!=']' ) exp( "']'" );
|
||||
toker->next();
|
||||
ExprNode *expr=d_new VarExprNode( var.release() );
|
||||
var=d_new VectorVarNode( expr,exprs.release() );
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return var.release();
|
||||
}
|
||||
|
||||
DeclNode *Parser::parseVarDecl( int kind,bool constant ){
|
||||
int pos=toker->pos();
|
||||
string ident=parseIdent();
|
||||
string tag=parseTypeTag();
|
||||
DeclNode *d;
|
||||
if( toker->curr()=='[' ){
|
||||
if( constant ) ex( "Blitz arrays may not be constant" );
|
||||
toker->next();
|
||||
a_ptr<ExprSeqNode> exprs( parseExprSeq() );
|
||||
if( exprs->size()!=1 || toker->curr()!=']' ) exp( "']'" );
|
||||
toker->next();
|
||||
d=d_new VectorDeclNode( ident,tag,exprs.release(),kind );
|
||||
}else{
|
||||
ExprNode *expr=0;
|
||||
if( toker->curr()=='=' ){
|
||||
toker->next();expr=parseExpr( false );
|
||||
}else if( constant ) ex( "Constants must be initialized" );
|
||||
d=d_new VarDeclNode( ident,tag,kind,constant,expr );
|
||||
}
|
||||
d->pos=pos;d->file=incfile;
|
||||
return d;
|
||||
}
|
||||
|
||||
DimNode *Parser::parseArrayDecl(){
|
||||
int pos=toker->pos();
|
||||
string ident=parseIdent();
|
||||
string tag=parseTypeTag();
|
||||
if( toker->curr()!='(' ) exp( "'('" );
|
||||
toker->next();a_ptr<ExprSeqNode> exprs( parseExprSeq() );
|
||||
if( toker->curr()!=')' ) exp( "')'" );
|
||||
if( !exprs->size() ) ex( "can't have a 0 dimensional array" );
|
||||
toker->next();
|
||||
DimNode *d=d_new DimNode( ident,tag,exprs.release() );
|
||||
arrayDecls[ident]=d;
|
||||
d->pos=pos;
|
||||
return d;
|
||||
}
|
||||
|
||||
DeclNode *Parser::parseFuncDecl(){
|
||||
int pos=toker->pos();
|
||||
string ident=parseIdent();
|
||||
string tag=parseTypeTag();
|
||||
if( toker->curr()!='(' ) exp( "'('" );
|
||||
a_ptr<DeclSeqNode> params( d_new DeclSeqNode() );
|
||||
if( toker->next()!=')' ){
|
||||
for(;;){
|
||||
params->push_back( parseVarDecl( DECL_PARAM,false ) );
|
||||
if( toker->curr()!=',' ) break;
|
||||
toker->next();
|
||||
}
|
||||
if( toker->curr()!=')' ) exp( "')'" );
|
||||
}
|
||||
toker->next();
|
||||
a_ptr<StmtSeqNode> stmts( parseStmtSeq( STMTS_BLOCK ) );
|
||||
if( toker->curr()!=ENDFUNCTION ) exp( "'End Function'" );
|
||||
StmtNode *ret=d_new ReturnNode(0);ret->pos=toker->pos();
|
||||
stmts->push_back( ret );toker->next();
|
||||
DeclNode *d=d_new FuncDeclNode( ident,tag,params.release(),stmts.release() );
|
||||
d->pos=pos;d->file=incfile;
|
||||
return d;
|
||||
}
|
||||
|
||||
DeclNode *Parser::parseStructDecl(){
|
||||
int pos=toker->pos();
|
||||
string ident=parseIdent();
|
||||
while( toker->curr()=='\n' ) toker->next();
|
||||
a_ptr<DeclSeqNode> fields( d_new DeclSeqNode() );
|
||||
while( toker->curr()==FIELD ){
|
||||
do{
|
||||
toker->next();
|
||||
fields->push_back( parseVarDecl( DECL_FIELD,false ) );
|
||||
}while( toker->curr()==',' );
|
||||
while( toker->curr()=='\n' ) toker->next();
|
||||
}
|
||||
if( toker->curr()!=ENDTYPE ) exp( "'Field' or 'End Type'" );
|
||||
toker->next();
|
||||
DeclNode *d=d_new StructDeclNode( ident,fields.release() );
|
||||
d->pos=pos;d->file=incfile;
|
||||
return d;
|
||||
}
|
||||
|
||||
IfNode *Parser::parseIf(){
|
||||
a_ptr<ExprNode> expr;
|
||||
a_ptr<StmtSeqNode> stmts,elseOpt;
|
||||
|
||||
expr=parseExpr( false );
|
||||
if( toker->curr()==THEN ) toker->next();
|
||||
|
||||
bool blkif=isTerm( toker->curr() );
|
||||
stmts=parseStmtSeq( blkif ? STMTS_BLOCK : STMTS_LINE );
|
||||
|
||||
if( toker->curr()==ELSEIF ){
|
||||
int pos=toker->pos();
|
||||
toker->next();
|
||||
IfNode *ifnode=parseIf();
|
||||
ifnode->pos=pos;
|
||||
elseOpt=d_new StmtSeqNode( incfile );
|
||||
elseOpt->push_back( ifnode );
|
||||
}else if( toker->curr()==ELSE ){
|
||||
toker->next();
|
||||
elseOpt=parseStmtSeq( blkif ? STMTS_BLOCK : STMTS_LINE );
|
||||
}
|
||||
if( blkif ){
|
||||
if( toker->curr()!=ENDIF ) exp( "'EndIf'" );
|
||||
}else if( toker->curr()!='\n' ) exp( "end-of-line" );
|
||||
|
||||
return d_new IfNode( expr.release(),stmts.release(),elseOpt.release() );
|
||||
}
|
||||
|
||||
ExprSeqNode *Parser::parseExprSeq(){
|
||||
a_ptr<ExprSeqNode> exprs( d_new ExprSeqNode() );
|
||||
bool opt=true;
|
||||
while( ExprNode *e=parseExpr( opt ) ){
|
||||
exprs->push_back( e );
|
||||
if( toker->curr()!=',' ) break;
|
||||
toker->next();opt=false;
|
||||
}
|
||||
return exprs.release();
|
||||
}
|
||||
|
||||
ExprNode *Parser::parseExpr( bool opt ){
|
||||
if( toker->curr()==NOT ){
|
||||
toker->next();
|
||||
ExprNode *expr=parseExpr1( false );
|
||||
return d_new RelExprNode( '=',expr,d_new IntConstNode( 0 ) );
|
||||
}
|
||||
return parseExpr1( opt );
|
||||
}
|
||||
|
||||
ExprNode *Parser::parseExpr1( bool opt ){
|
||||
|
||||
a_ptr<ExprNode> lhs( parseExpr2( opt ) );
|
||||
if( !lhs ) return 0;
|
||||
for(;;){
|
||||
int c=toker->curr();
|
||||
if( c!=AND && c!=OR && c!=XOR ) return lhs.release();
|
||||
toker->next();ExprNode *rhs=parseExpr2( false );
|
||||
lhs=d_new BinExprNode( c,lhs.release(),rhs );
|
||||
}
|
||||
}
|
||||
|
||||
ExprNode *Parser::parseExpr2( bool opt ){
|
||||
|
||||
a_ptr<ExprNode> lhs( parseExpr3( opt ) );
|
||||
if( !lhs ) return 0;
|
||||
for(;;){
|
||||
int c=toker->curr();
|
||||
if( c!='<' && c!='>' && c!='=' && c!=LE && c!=GE && c!=NE ) return lhs.release();
|
||||
toker->next();ExprNode *rhs=parseExpr3( false );
|
||||
lhs=d_new RelExprNode( c,lhs.release(),rhs );
|
||||
}
|
||||
}
|
||||
|
||||
ExprNode *Parser::parseExpr3( bool opt ){
|
||||
|
||||
a_ptr<ExprNode> lhs( parseExpr4( opt ) );
|
||||
if( !lhs ) return 0;
|
||||
for(;;){
|
||||
int c=toker->curr();
|
||||
if( c!='+' && c!='-' ) return lhs.release();
|
||||
toker->next();ExprNode *rhs=parseExpr4( false );
|
||||
lhs=d_new ArithExprNode( c,lhs.release(),rhs );
|
||||
}
|
||||
}
|
||||
|
||||
ExprNode *Parser::parseExpr4( bool opt ){
|
||||
a_ptr<ExprNode> lhs( parseExpr5( opt ) );
|
||||
if( !lhs ) return 0;
|
||||
for(;;){
|
||||
int c=toker->curr();
|
||||
if( c!=SHL && c!=SHR && c!=SAR ) return lhs.release();
|
||||
toker->next();ExprNode *rhs=parseExpr5( false );
|
||||
lhs=d_new BinExprNode( c,lhs.release(),rhs );
|
||||
}
|
||||
}
|
||||
|
||||
ExprNode *Parser::parseExpr5( bool opt ){
|
||||
|
||||
a_ptr<ExprNode> lhs( parseExpr6( opt ) );
|
||||
if( !lhs ) return 0;
|
||||
for(;;){
|
||||
int c=toker->curr();
|
||||
if( c!='*' && c!='/' && c!=MOD ) return lhs.release();
|
||||
toker->next();ExprNode *rhs=parseExpr6( false );
|
||||
lhs=d_new ArithExprNode( c,lhs.release(),rhs );
|
||||
}
|
||||
}
|
||||
|
||||
ExprNode *Parser::parseExpr6( bool opt ){
|
||||
|
||||
a_ptr<ExprNode> lhs( parseUniExpr( opt ) );
|
||||
if( !lhs ) return 0;
|
||||
for(;;){
|
||||
int c=toker->curr();
|
||||
if( c!='^' ) return lhs.release();
|
||||
toker->next();ExprNode *rhs=parseUniExpr( false );
|
||||
lhs=d_new ArithExprNode( c,lhs.release(),rhs );
|
||||
}
|
||||
}
|
||||
|
||||
ExprNode *Parser::parseUniExpr( bool opt ){
|
||||
|
||||
ExprNode *result=0;
|
||||
string t;
|
||||
|
||||
int c=toker->curr();
|
||||
switch( c ){
|
||||
case BBINT:
|
||||
if( toker->next()=='%' ) toker->next();
|
||||
result=parseUniExpr( false );
|
||||
result=d_new CastNode( result,Type::int_type );
|
||||
break;
|
||||
case BBFLOAT:
|
||||
if( toker->next()=='#' ) toker->next();
|
||||
result=parseUniExpr( false );
|
||||
result=d_new CastNode( result,Type::float_type );
|
||||
break;
|
||||
case BBSTR:
|
||||
if( toker->next()=='$' ) toker->next();
|
||||
result=parseUniExpr( false );
|
||||
result=d_new CastNode( result,Type::string_type );
|
||||
break;
|
||||
case OBJECT:
|
||||
if( toker->next()=='.' ) toker->next();
|
||||
t=parseIdent();
|
||||
result=parseUniExpr( false );
|
||||
result=d_new ObjectCastNode( result,t );
|
||||
break;
|
||||
case BBHANDLE:
|
||||
toker->next();
|
||||
result=parseUniExpr( false );
|
||||
result=d_new ObjectHandleNode( result );
|
||||
break;
|
||||
case BEFORE:
|
||||
toker->next();
|
||||
result=parseUniExpr( false );
|
||||
result=d_new BeforeNode( result );
|
||||
break;
|
||||
case AFTER:
|
||||
toker->next();
|
||||
result=parseUniExpr( false );
|
||||
result=d_new AfterNode( result );
|
||||
break;
|
||||
case '+':case '-':case '~':case ABS:case SGN:
|
||||
toker->next();
|
||||
result=parseUniExpr( false );
|
||||
if( c=='~' ){
|
||||
result=d_new BinExprNode( XOR,result,d_new IntConstNode( -1 ) );
|
||||
}else{
|
||||
result=d_new UniExprNode( c,result );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result=parsePrimary( opt );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ExprNode *Parser::parsePrimary( bool opt ){
|
||||
|
||||
a_ptr<ExprNode> expr;
|
||||
string t,ident,tag;
|
||||
ExprNode *result=0;
|
||||
int n,k;
|
||||
|
||||
switch( toker->curr() ){
|
||||
case '(':
|
||||
toker->next();
|
||||
expr=parseExpr( false );
|
||||
if( toker->curr()!=')' ) exp( "')'" );
|
||||
toker->next();
|
||||
result=expr.release();
|
||||
break;
|
||||
case BBNEW:
|
||||
toker->next();t=parseIdent();
|
||||
result=d_new NewNode( t );
|
||||
break;
|
||||
case FIRST:
|
||||
toker->next();t=parseIdent();
|
||||
result=d_new FirstNode( t );
|
||||
break;
|
||||
case LAST:
|
||||
toker->next();t=parseIdent();
|
||||
result=d_new LastNode( t );
|
||||
break;
|
||||
case BBNULL:
|
||||
result=d_new NullNode();
|
||||
toker->next();
|
||||
break;
|
||||
case INTCONST:
|
||||
result=d_new IntConstNode( atoi( toker->text() ) );
|
||||
toker->next();
|
||||
break;
|
||||
case FLOATCONST:
|
||||
result=d_new FloatConstNode( atof( toker->text() ) );
|
||||
toker->next();
|
||||
break;
|
||||
case STRINGCONST:
|
||||
t=toker->text();
|
||||
result=d_new StringConstNode( t.substr( 1,t.size()-2 ) );
|
||||
toker->next();
|
||||
break;
|
||||
case BINCONST:
|
||||
n=0;t=toker->text();
|
||||
for( k=1;k<t.size();++k ) n=(n<<1)|(t[k]=='1');
|
||||
result=d_new IntConstNode( n );
|
||||
toker->next();
|
||||
break;
|
||||
case HEXCONST:
|
||||
n=0;t=toker->text();
|
||||
for( k=1;k<t.size();++k ) n=(n<<4)|( isdigit(t[k]) ? t[k]&0xf : (t[k]&7)+9 );
|
||||
result=d_new IntConstNode( n );
|
||||
toker->next();
|
||||
break;
|
||||
case PI:
|
||||
result=d_new FloatConstNode( 3.1415926535897932384626433832795f );
|
||||
toker->next();break;
|
||||
case BBTRUE:
|
||||
result=d_new IntConstNode( 1 );
|
||||
toker->next();break;
|
||||
case BBFALSE:
|
||||
result=d_new IntConstNode( 0 );
|
||||
toker->next();break;
|
||||
case IDENT:
|
||||
ident=toker->text();
|
||||
toker->next();tag=parseTypeTag();
|
||||
if( toker->curr()=='(' && arrayDecls.find(ident)==arrayDecls.end() ){
|
||||
//must be a func
|
||||
toker->next();
|
||||
a_ptr<ExprSeqNode> exprs( parseExprSeq() );
|
||||
if( toker->curr()!=')' ) exp( "')'" );
|
||||
toker->next();
|
||||
result=d_new CallNode( ident,tag,exprs.release() );
|
||||
}else{
|
||||
//must be a var
|
||||
VarNode *var=parseVar( ident,tag );
|
||||
result=d_new VarExprNode( var );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if( !opt ) exp( "expression" );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
/*
|
||||
|
||||
The parser builds an abstact syntax tree from input tokens.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
#include "toker.h"
|
||||
#include "nodes.h"
|
||||
|
||||
class Parser{
|
||||
public:
|
||||
|
||||
Parser( Toker &t );
|
||||
|
||||
ProgNode *parse( const string &main );
|
||||
|
||||
private:
|
||||
string incfile;
|
||||
set<string> included;
|
||||
Toker *toker,*main_toker;
|
||||
map<string,DimNode*> arrayDecls;
|
||||
|
||||
DeclSeqNode *consts;
|
||||
DeclSeqNode *structs;
|
||||
DeclSeqNode *funcs;
|
||||
DeclSeqNode *datas;
|
||||
|
||||
StmtSeqNode *parseStmtSeq( int scope );
|
||||
void parseStmtSeq( StmtSeqNode *stmts,int scope );
|
||||
|
||||
void ex( const string &s );
|
||||
void exp( const string &s );
|
||||
|
||||
string parseIdent();
|
||||
void parseChar( int c );
|
||||
string parseTypeTag();
|
||||
|
||||
VarNode *parseVar();
|
||||
VarNode *parseVar( const string &ident,const string &tag );
|
||||
CallNode *parseCall( const string &ident,const string &tag );
|
||||
IfNode *parseIf();
|
||||
|
||||
DeclNode *parseVarDecl( int kind,bool constant );
|
||||
DimNode *parseArrayDecl();
|
||||
DeclNode *parseFuncDecl();
|
||||
DeclNode *parseStructDecl();
|
||||
|
||||
ExprSeqNode *parseExprSeq();
|
||||
|
||||
ExprNode *parseExpr( bool opt );
|
||||
ExprNode *parseExpr1( bool opt ); //And, Or, Eor
|
||||
ExprNode *parseExpr2( bool opt ); //<,=,>,<=,<>,>=
|
||||
ExprNode *parseExpr3( bool opt ); //+,-
|
||||
ExprNode *parseExpr4( bool opt ); //Lsr,Lsr,Asr
|
||||
ExprNode *parseExpr5( bool opt ); //*,/,Mod
|
||||
ExprNode *parseExpr6( bool opt ); //^
|
||||
ExprNode *parseUniExpr( bool opt ); //+,-,Not,~
|
||||
ExprNode *parsePrimary( bool opt );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "nodes.h"
|
||||
|
||||
//////////////////
|
||||
// The program! //
|
||||
//////////////////
|
||||
Environ *ProgNode::semant( Environ *e ){
|
||||
|
||||
file_lab=genLabel();
|
||||
|
||||
StmtSeqNode::reset( stmts->file,file_lab );
|
||||
|
||||
a_ptr<Environ> env( d_new Environ( genLabel(),Type::int_type,0,e ) );
|
||||
|
||||
consts->proto( env->decls,env );
|
||||
structs->proto( env->typeDecls,env );
|
||||
structs->semant( env );
|
||||
funcs->proto( env->funcDecls,env );
|
||||
stmts->semant( env );
|
||||
funcs->semant( env );
|
||||
datas->proto( env->decls,env );
|
||||
datas->semant( env );
|
||||
|
||||
sem_env=env.release();
|
||||
return sem_env;
|
||||
}
|
||||
|
||||
void ProgNode::translate( Codegen *g,const vector<UserFunc> &usrfuncs ){
|
||||
|
||||
int k;
|
||||
|
||||
if( g->debug ) g->s_data( stmts->file,file_lab );
|
||||
|
||||
//enumerate locals
|
||||
int size=enumVars( sem_env );
|
||||
|
||||
//'Main' label
|
||||
g->enter( "__MAIN",size );
|
||||
|
||||
//reset data pointer
|
||||
g->code( call( "__bbRestore",global( "__DATA" ) ) );
|
||||
|
||||
//load external libs
|
||||
g->code( call( "__bbLoadLibs",global( "__LIBS" ) ) );
|
||||
|
||||
//call main program
|
||||
g->code( jsr( sem_env->funcLabel+"_begin" ) );
|
||||
g->code( jump( sem_env->funcLabel+"_leave" ) );
|
||||
g->label( sem_env->funcLabel+"_begin" );
|
||||
|
||||
//create locals
|
||||
TNode *t=createVars( sem_env );
|
||||
if( t ) g->code( t );
|
||||
if( g->debug ){
|
||||
string t=genLabel();
|
||||
g->s_data( "<main program>",t );
|
||||
g->code( call( "__bbDebugEnter",local(0),iconst((int)sem_env),global(t) ) );
|
||||
}
|
||||
|
||||
//no user funcs used!
|
||||
usedfuncs.clear();
|
||||
|
||||
//program statements
|
||||
stmts->translate( g );
|
||||
|
||||
//emit return
|
||||
g->code( ret() );
|
||||
|
||||
//check labels
|
||||
for( k=0;k<sem_env->labels.size();++k ){
|
||||
if( sem_env->labels[k]->def<0 ) ex( "Undefined label '"+sem_env->labels[k]->name+"'",sem_env->labels[k]->ref,stmts->file );
|
||||
}
|
||||
|
||||
//leave main program
|
||||
g->label( sem_env->funcLabel+"_leave" );
|
||||
t=deleteVars( sem_env );
|
||||
if( g->debug ) t=d_new TNode( IR_SEQ,call( "__bbDebugLeave" ),t );
|
||||
g->leave( t,0 );
|
||||
|
||||
//structs
|
||||
structs->translate( g );
|
||||
|
||||
//non-main functions
|
||||
funcs->translate( g );
|
||||
|
||||
//data
|
||||
datas->translate( g );
|
||||
|
||||
//library functions
|
||||
map<string,vector<int> > libFuncs;
|
||||
|
||||
//lib ptrs
|
||||
g->flush();
|
||||
g->align_data(4);
|
||||
for( k=0;k<usrfuncs.size();++k ){
|
||||
const UserFunc &fn=usrfuncs[k];
|
||||
|
||||
if( !usedfuncs.count(fn.ident) ) continue;
|
||||
|
||||
libFuncs[fn.lib].push_back( k );
|
||||
|
||||
g->i_data( 0,"_f"+fn.ident );
|
||||
}
|
||||
|
||||
//LIBS chunk
|
||||
g->flush();
|
||||
g->label( "__LIBS" );
|
||||
map<string,vector<int> >::const_iterator lf_it;
|
||||
for( lf_it=libFuncs.begin();lf_it!=libFuncs.end();++lf_it ){
|
||||
|
||||
//lib name
|
||||
g->s_data( lf_it->first );
|
||||
|
||||
const vector<int> &fns=lf_it->second;
|
||||
|
||||
for( int j=0;j<fns.size();++j ){
|
||||
const UserFunc &fn=usrfuncs[ fns[j] ];
|
||||
|
||||
//proc name
|
||||
g->s_data( fn.proc );
|
||||
|
||||
g->p_data( "_f"+fn.ident );
|
||||
}
|
||||
g->s_data( "" );
|
||||
}
|
||||
g->s_data( "" );
|
||||
|
||||
//DATA chunk
|
||||
g->flush();
|
||||
g->align_data( 4 );
|
||||
g->label( "__DATA" );
|
||||
datas->transdata( g );
|
||||
g->i_data(0);
|
||||
|
||||
//Thats IT!
|
||||
g->flush();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#ifndef PROGNODE_H
|
||||
#define PROGNODE_H
|
||||
|
||||
#include "node.h"
|
||||
#include "codegen.h"
|
||||
|
||||
struct UserFunc{
|
||||
string ident,proc,lib;
|
||||
UserFunc( const UserFunc &t ):ident(t.ident),proc(t.proc),lib(t.lib){}
|
||||
UserFunc( const string &id,const string &pr,const string &lb ):ident(id),proc(pr),lib(lb){}
|
||||
};
|
||||
|
||||
struct ProgNode : public Node{
|
||||
|
||||
DeclSeqNode *consts;
|
||||
DeclSeqNode *structs;
|
||||
DeclSeqNode *funcs;
|
||||
DeclSeqNode *datas;
|
||||
StmtSeqNode *stmts;
|
||||
|
||||
Environ *sem_env;
|
||||
|
||||
string file_lab;
|
||||
|
||||
ProgNode( DeclSeqNode *c,DeclSeqNode *s,DeclSeqNode *f,DeclSeqNode *d,StmtSeqNode *ss ):consts(c),structs(s),funcs(f),datas(d),stmts(ss){}
|
||||
~ProgNode(){
|
||||
delete consts;
|
||||
delete structs;
|
||||
delete funcs;
|
||||
delete datas;
|
||||
delete stmts;
|
||||
}
|
||||
|
||||
Environ *semant( Environ *e );
|
||||
void translate( Codegen *g,const vector<UserFunc> &userfuncs );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
Classes:
|
||||
|
||||
ProgNode - output of parse - tree of Nodes
|
||||
TProg - output of translate - vector of TNodes
|
||||
string - output of codegen
|
||||
Module - output of assemble
|
||||
|
||||
reserved asm labels.
|
||||
|
||||
_b???? reserved for private blitz lib calls
|
||||
_l???? reserved for compiler generated labels
|
||||
_c???? reserved for codegen generated labels
|
||||
_a???? reserved for asm generated labels
|
||||
|
||||
Codegen should probably be able to create it's own 'data' for constants.
|
||||
|
||||
The IR_CONST instruction may have to generate a label to store, say,
|
||||
strings (and floats on x86?)
|
||||
|
||||
|
||||
* libs prototype info:
|
||||
|
||||
graphics%%% - 3 int args
|
||||
rect%%%% - 4 int args
|
||||
vwait
|
||||
%mousex - int result
|
||||
%mousey - int result
|
||||
<Image>loadImage$ - obj result, 1 string arg
|
||||
|
||||
* floats, strings, user types
|
||||
|
||||
Stick with old BB newtypes:
|
||||
|
||||
NewType mytype
|
||||
x.f:y.f:z.f
|
||||
image.Image
|
||||
End NewType
|
||||
|
||||
Dim List lst.mytype
|
||||
Dim Queue que.mytype
|
||||
Dim Vector vec.mytype
|
||||
|
||||
test=new mytype
|
||||
test\x=100
|
||||
test\y=100
|
||||
test\z=100
|
||||
|
||||
name="Hello"
|
||||
|
||||
move test
|
||||
|
||||
statement move t.mytype
|
||||
t\x=t\x+t\xs
|
||||
t\y=t\y+t\ys
|
||||
end statement
|
||||
|
||||
* stop/step/continue/debug
|
||||
|
||||
* error handling
|
||||
|
||||
Errors are sent to cerr, and an exception thrown.
|
||||
|
||||
Error string format:
|
||||
|
||||
E charpos message - eg:
|
||||
|
||||
cerr<<"E 100 Blitz expects an identifier here"<<endl;
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
void ExprSeqNode::semant( Scope *s ){
|
||||
|
||||
for( int k=0;k<exprs.size();++k ) exprs[k]->semant( s );
|
||||
type=Type::int_type;
|
||||
}
|
||||
|
||||
void SimpleVarNode::semant( Scope *s ){
|
||||
|
||||
if( type=s->findIdent( ident ) ) return;
|
||||
s->insertIdent( ident,Type::int_type );
|
||||
}
|
||||
|
||||
void LabelNode::semant( Scope *s ){
|
||||
|
||||
Type *t=s->findIdent( label );
|
||||
if( !t ){
|
||||
s->insertIdent( label,new LabelType( this ) );
|
||||
return;
|
||||
}
|
||||
if( t->labelType() && !t->labelType()->defn ){
|
||||
t->labelType()->defn=this;
|
||||
return;
|
||||
}
|
||||
semantEx( "Duplicate identifier" );
|
||||
}
|
||||
|
||||
void GotoNode::semant( Scope *s ){
|
||||
|
||||
Type *t=s->findIdent( label );
|
||||
if( !t ){
|
||||
s->insertIdent( label,new LabelType(0) );
|
||||
return;
|
||||
}
|
||||
if( t->labelType() ) return;
|
||||
semantEx( "Duplicate Identifier" );
|
||||
}
|
||||
|
||||
void ProgNode::semant( Scope *s ){
|
||||
|
||||
StmtSeqNode::semant( s );
|
||||
map<string,Type*>::iterator it;
|
||||
for( it=s->idents.begin();it!=s->idents.end();++it ){
|
||||
if( LabelType *l=it->second->labelType() ){
|
||||
if( !l->defn ){
|
||||
semantEx( "Undefined Label" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "std.h"
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
#ifndef STD_COMPILER_H
|
||||
#define STD_COMPILER_H
|
||||
|
||||
#include "../config/config.h"
|
||||
#include "../stdutil/stdutil.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,586 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "nodes.h"
|
||||
|
||||
static string fileLabel;
|
||||
static map<string,string> fileMap;
|
||||
|
||||
void StmtNode::debug( int pos,Codegen *g ){
|
||||
if( g->debug ){
|
||||
TNode *t=fileLabel.size() ? global( fileLabel ) : iconst(0);
|
||||
g->code( call( "__bbDebugStmt",iconst( pos ),t ) );
|
||||
}
|
||||
}
|
||||
|
||||
void StmtSeqNode::reset( const string &file,const string &lab ){
|
||||
fileLabel="";
|
||||
fileMap.clear();
|
||||
|
||||
fileMap[file]=lab;
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// Statement Sequence //
|
||||
////////////////////////
|
||||
void StmtSeqNode::semant( Environ *e ){
|
||||
for( int k=0;k<stmts.size();++k ){
|
||||
try{ stmts[k]->semant( e ); }
|
||||
catch( Ex &x ){
|
||||
if( x.pos<0 ) x.pos=stmts[k]->pos;
|
||||
if( !x.file.size() ) x.file=file;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StmtSeqNode::translate( Codegen *g ){
|
||||
|
||||
string t=fileLabel;
|
||||
fileLabel=file.size() ? fileMap[file] : "";
|
||||
for( int k=0;k<stmts.size();++k ){
|
||||
StmtNode *stmt=stmts[k];
|
||||
stmt->debug( stmts[k]->pos,g );
|
||||
try{
|
||||
stmt->translate( g );
|
||||
}
|
||||
catch( Ex &x ){
|
||||
if( x.pos<0 ) x.pos=stmts[k]->pos;
|
||||
if( !x.file.size() ) x.file=file;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
fileLabel=t;
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// An Include! //
|
||||
/////////////////
|
||||
void IncludeNode::semant( Environ *e ){
|
||||
|
||||
label=genLabel();
|
||||
fileMap[file]=label;
|
||||
|
||||
stmts->semant( e );
|
||||
}
|
||||
|
||||
void IncludeNode::translate( Codegen *g ){
|
||||
|
||||
if( g->debug ) g->s_data( file,label );
|
||||
|
||||
stmts->translate( g );
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// a declaration //
|
||||
///////////////////
|
||||
void DeclStmtNode::semant( Environ *e ){
|
||||
decl->proto( e->decls,e );
|
||||
decl->semant( e );
|
||||
}
|
||||
|
||||
void DeclStmtNode::translate( Codegen *g ){
|
||||
decl->translate( g );
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// Dim AND declare an Array //
|
||||
//////////////////////////////
|
||||
void DimNode::semant( Environ *e ){
|
||||
Type *t=tagType( tag,e );
|
||||
if( Decl *d=e->findDecl( ident ) ){
|
||||
ArrayType *a=d->type->arrayType();
|
||||
if( !a || a->dims!=exprs->size() || (t && a->elementType!=t) ){
|
||||
ex( "Duplicate identifier" );
|
||||
}
|
||||
sem_type=a;sem_decl=0;
|
||||
}else{
|
||||
if( e->level>0 ) ex( "Array not found in main program" );
|
||||
if( !t ) t=Type::int_type;
|
||||
sem_type=d_new ArrayType( t,exprs->size() );
|
||||
sem_decl=e->decls->insertDecl( ident,sem_type,DECL_ARRAY );
|
||||
e->types.push_back( sem_type );
|
||||
}
|
||||
exprs->semant( e );
|
||||
exprs->castTo( Type::int_type,e );
|
||||
}
|
||||
|
||||
void DimNode::translate( Codegen *g ){
|
||||
TNode *t;
|
||||
g->code( call( "__bbUndimArray",global( "_a"+ident ) ) );
|
||||
for( int k=0;k<exprs->size();++k ){
|
||||
t=add( global( "_a"+ident ),iconst( k*4+12 ) );
|
||||
t=move( exprs->exprs[k]->translate(g),mem( t ) );
|
||||
g->code( t );
|
||||
}
|
||||
g->code( call( "__bbDimArray",global( "_a"+ident ) ) );
|
||||
|
||||
if( !sem_decl ) return;
|
||||
|
||||
int et;
|
||||
Type *ty=sem_type->arrayType()->elementType;
|
||||
if( ty==Type::int_type ) et=1;
|
||||
else if( ty==Type::float_type ) et=2;
|
||||
else if( ty==Type::string_type ) et=3;
|
||||
else et=5;
|
||||
|
||||
g->align_data( 4 );
|
||||
g->i_data( 0,"_a"+ident );
|
||||
g->i_data( et );
|
||||
g->i_data( exprs->size() );
|
||||
for( k=0;k<exprs->size();++k ) g->i_data( 0 );
|
||||
}
|
||||
|
||||
////////////////
|
||||
// Assignment //
|
||||
////////////////
|
||||
void AssNode::semant( Environ *e ){
|
||||
var->semant( e );
|
||||
if( var->sem_type->constType() ) ex( "Constants can not be assigned to" );
|
||||
if( var->sem_type->vectorType() ) ex( "Blitz arrays can not be assigned to" );
|
||||
expr=expr->semant( e );
|
||||
expr=expr->castTo( var->sem_type,e );
|
||||
}
|
||||
|
||||
void AssNode::translate( Codegen *g ){
|
||||
g->code( var->store( g,expr->translate( g ) ) );
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
// Expression statement //
|
||||
//////////////////////////
|
||||
void ExprStmtNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
}
|
||||
|
||||
void ExprStmtNode::translate( Codegen *g ){
|
||||
TNode *t=expr->translate( g );
|
||||
if( expr->sem_type==Type::string_type ) t=call( "__bbStrRelease",t );
|
||||
g->code( t );
|
||||
}
|
||||
|
||||
////////////////
|
||||
// user label //
|
||||
////////////////
|
||||
void LabelNode::semant( Environ *e ){
|
||||
if( Label *l=e->findLabel( ident ) ){
|
||||
if( l->def>=0 ) ex( "duplicate label" );
|
||||
l->def=pos;l->data_sz=data_sz;
|
||||
}else e->insertLabel( ident,pos,-1,data_sz );
|
||||
ident=e->funcLabel+ident;
|
||||
}
|
||||
|
||||
void LabelNode::translate( Codegen *g ){
|
||||
g->label( "_l"+ident );
|
||||
}
|
||||
|
||||
//////////////////
|
||||
// Restore data //
|
||||
//////////////////
|
||||
void RestoreNode::semant( Environ *e ){
|
||||
if( e->level>0 ) e=e->globals;
|
||||
|
||||
if( ident.size()==0 ) sem_label=0;
|
||||
else{
|
||||
sem_label=e->findLabel( ident );
|
||||
if( !sem_label ) sem_label=e->insertLabel( ident,-1,pos,-1 );
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreNode::translate( Codegen *g ){
|
||||
TNode *t=global( "__DATA" );
|
||||
if( sem_label ) t=add( t,iconst( sem_label->data_sz*8 ) );
|
||||
g->code( call( "__bbRestore",t ) );
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Goto statement //
|
||||
////////////////////
|
||||
void GotoNode::semant( Environ *e ){
|
||||
if( !e->findLabel( ident ) ){
|
||||
e->insertLabel( ident,-1,pos,-1 );
|
||||
}
|
||||
ident=e->funcLabel+ident;
|
||||
}
|
||||
|
||||
void GotoNode::translate( Codegen *g ){
|
||||
g->code( jump( "_l"+ident ) );
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
// Gosub statement //
|
||||
/////////////////////
|
||||
void GosubNode::semant( Environ *e ){
|
||||
if( e->level>0 ) ex( "'Gosub' may not be used inside a function" );
|
||||
if( !e->findLabel( ident ) ) e->insertLabel( ident,-1,pos,-1 );
|
||||
ident=e->funcLabel+ident;
|
||||
}
|
||||
|
||||
void GosubNode::translate( Codegen *g ){
|
||||
g->code( jsr( "_l"+ident ) );
|
||||
}
|
||||
|
||||
//////////////////
|
||||
// If statement //
|
||||
//////////////////
|
||||
void IfNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
expr=expr->castTo( Type::int_type,e );
|
||||
stmts->semant( e );
|
||||
if( elseOpt ) elseOpt->semant( e );
|
||||
}
|
||||
|
||||
void IfNode::translate( Codegen *g ){
|
||||
if( ConstNode *c=expr->constNode() ){
|
||||
if( c->intValue() ) stmts->translate( g );
|
||||
else if( elseOpt ) elseOpt->translate( g );
|
||||
}else{
|
||||
string _else=genLabel();
|
||||
g->code( jumpf( expr->translate( g ),_else ) );
|
||||
stmts->translate( g );
|
||||
if( elseOpt ){
|
||||
string _else2=genLabel();
|
||||
g->code( jump( _else2 ) );
|
||||
g->label( _else );
|
||||
elseOpt->translate( g );
|
||||
_else=_else2;
|
||||
}
|
||||
g->label( _else );
|
||||
}
|
||||
}
|
||||
|
||||
///////////
|
||||
// Break //
|
||||
///////////
|
||||
void ExitNode::semant( Environ *e ){
|
||||
sem_brk=e->breakLabel;
|
||||
if( !sem_brk.size() ) ex( "break must appear inside a loop" );
|
||||
}
|
||||
|
||||
void ExitNode::translate( Codegen *g ){
|
||||
g->code( d_new TNode( IR_JUMP,0,0,sem_brk ) );
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
// While statement //
|
||||
/////////////////////
|
||||
void WhileNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
expr=expr->castTo( Type::int_type,e );
|
||||
string brk=e->setBreak( sem_brk=genLabel() );
|
||||
stmts->semant( e );
|
||||
e->setBreak( brk );
|
||||
}
|
||||
|
||||
void WhileNode::translate( Codegen *g ){
|
||||
string loop=genLabel();
|
||||
if( ConstNode *c=expr->constNode() ){
|
||||
if( !c->intValue() ) return;
|
||||
g->label( loop );
|
||||
stmts->translate( g );
|
||||
g->code( jump( loop ) );
|
||||
}else{
|
||||
string cond=genLabel();
|
||||
g->code( jump( cond ) );
|
||||
g->label( loop );
|
||||
stmts->translate( g );
|
||||
debug( wendPos,g );
|
||||
g->label( cond );
|
||||
g->code( jumpt( expr->translate( g ),loop ) );
|
||||
}
|
||||
g->label( sem_brk );
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// For/Next loop //
|
||||
///////////////////
|
||||
ForNode::ForNode( VarNode *var,ExprNode *from,ExprNode *to,ExprNode *step,StmtSeqNode *ss,int np )
|
||||
:var(var),fromExpr(from),toExpr(to),stepExpr(step),stmts(ss),nextPos(np){
|
||||
}
|
||||
|
||||
ForNode::~ForNode(){
|
||||
delete stmts;
|
||||
delete stepExpr;
|
||||
delete toExpr;
|
||||
delete fromExpr;
|
||||
delete var;
|
||||
}
|
||||
|
||||
void ForNode::semant( Environ *e ){
|
||||
var->semant( e );
|
||||
Type *ty=var->sem_type;
|
||||
if( ty->constType() ) ex( "Index variable can not be constant" );
|
||||
if( ty!=Type::int_type && ty!=Type::float_type ){
|
||||
ex( "index variable must be integer or real" );
|
||||
}
|
||||
fromExpr=fromExpr->semant( e );
|
||||
fromExpr=fromExpr->castTo( ty,e );
|
||||
toExpr=toExpr->semant( e );
|
||||
toExpr=toExpr->castTo( ty,e );
|
||||
stepExpr=stepExpr->semant( e );
|
||||
stepExpr=stepExpr->castTo( ty,e );
|
||||
|
||||
if( !stepExpr->constNode() ) ex( "Step value must be constant" );
|
||||
|
||||
string brk=e->setBreak( sem_brk=genLabel() );
|
||||
stmts->semant( e );
|
||||
e->setBreak( brk );
|
||||
}
|
||||
|
||||
void ForNode::translate( Codegen *g ){
|
||||
|
||||
TNode *t;Type *ty=var->sem_type;
|
||||
|
||||
//initial assignment
|
||||
g->code( var->store( g,fromExpr->translate( g ) ) );
|
||||
|
||||
string cond=genLabel();
|
||||
string loop=genLabel();
|
||||
g->code( jump( cond ) );
|
||||
g->label( loop );
|
||||
stmts->translate( g );
|
||||
|
||||
//execute the step part
|
||||
debug( nextPos,g );
|
||||
int op=ty==Type::int_type ? IR_ADD : IR_FADD;
|
||||
t=d_new TNode( op,var->load( g ),stepExpr->translate( g ) );
|
||||
g->code( var->store( g,t ) );
|
||||
|
||||
//test for loop cond
|
||||
g->label( cond );
|
||||
op=stepExpr->constNode()->floatValue()>0 ? '>' : '<';
|
||||
t=compare( op,var->load( g ),toExpr->translate( g ),ty );
|
||||
g->code( jumpf( t,loop ) );
|
||||
|
||||
g->label( sem_brk );
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// For each object of a type //
|
||||
///////////////////////////////
|
||||
void ForEachNode::semant( Environ *e ){
|
||||
var->semant( e );
|
||||
Type *ty=var->sem_type;
|
||||
|
||||
if( ty->structType()==0 ) ex( "Index variable is not a NewType" );
|
||||
Type *t=e->findType( typeIdent );
|
||||
if( !t ) ex( "Type name not found" );
|
||||
if( t!=ty ) ex( "Type mismatch" );
|
||||
|
||||
string brk=e->setBreak( sem_brk=genLabel() );
|
||||
stmts->semant( e );
|
||||
e->setBreak( brk );
|
||||
}
|
||||
|
||||
void ForEachNode::translate( Codegen *g ){
|
||||
TNode *t,*l,*r;
|
||||
string _loop=genLabel();
|
||||
|
||||
string objFirst,objNext;
|
||||
|
||||
if( var->isObjParam() ){
|
||||
objFirst="__bbObjEachFirst2";
|
||||
objNext="__bbObjEachNext2";
|
||||
}else{
|
||||
objFirst="__bbObjEachFirst";
|
||||
objNext="__bbObjEachNext";
|
||||
}
|
||||
|
||||
l=var->translate( g );
|
||||
r=global( "_t"+typeIdent );
|
||||
t=jumpf( call( objFirst,l,r ),sem_brk );
|
||||
g->code( t );
|
||||
|
||||
g->label( _loop );
|
||||
stmts->translate( g );
|
||||
|
||||
debug( nextPos,g );
|
||||
t=jumpt( call( objNext,var->translate( g ) ),_loop );
|
||||
g->code( t );
|
||||
|
||||
g->label( sem_brk );
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Return from a function //
|
||||
////////////////////////////
|
||||
void ReturnNode::semant( Environ *e ){
|
||||
if( e->level<=0 && expr ){
|
||||
ex( "Main program cannot return a value" );
|
||||
}
|
||||
if( e->level>0 ){
|
||||
if( !expr ){
|
||||
if( e->returnType==Type::float_type ){
|
||||
expr=d_new FloatConstNode( 0 );
|
||||
}else if( e->returnType==Type::string_type ){
|
||||
expr=d_new StringConstNode( "" );
|
||||
}else if( e->returnType->structType() ){
|
||||
expr=d_new NullNode();
|
||||
}else{
|
||||
expr=d_new IntConstNode( 0 );
|
||||
}
|
||||
}
|
||||
expr=expr->semant( e );
|
||||
expr=expr->castTo( e->returnType,e );
|
||||
returnLabel=e->funcLabel+"_leave";
|
||||
}
|
||||
}
|
||||
|
||||
void ReturnNode::translate( Codegen *g ){
|
||||
if( !expr ){
|
||||
g->code( d_new TNode( IR_RET,0,0 ) );
|
||||
return;
|
||||
}
|
||||
|
||||
TNode *t=expr->translate( g );
|
||||
|
||||
if( expr->sem_type==Type::float_type ){
|
||||
g->code( d_new TNode( IR_FRETURN,t,0,returnLabel ) );
|
||||
}else{
|
||||
g->code( d_new TNode( IR_RETURN,t,0,returnLabel ) );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Delete statement //
|
||||
//////////////////////
|
||||
void DeleteNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
if( expr->sem_type->structType()==0 ) ex( "Can't delete non-Newtype" );
|
||||
}
|
||||
|
||||
void DeleteNode::translate( Codegen *g ){
|
||||
TNode *t=expr->translate( g );
|
||||
g->code( call( "__bbObjDelete",t ) );
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Delete each of a type //
|
||||
///////////////////////////
|
||||
void DeleteEachNode::semant( Environ *e ){
|
||||
Type *t=e->findType( typeIdent );
|
||||
if( !t || t->structType()==0 ) ex( "Specified name is not a NewType name" );
|
||||
}
|
||||
|
||||
void DeleteEachNode::translate( Codegen *g ){
|
||||
g->code( call( "__bbObjDeleteEach",global( "_t"+typeIdent ) ) );
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Insert object in list //
|
||||
///////////////////////////
|
||||
void InsertNode::semant( Environ *e ){
|
||||
expr1=expr1->semant( e );
|
||||
expr2=expr2->semant( e );
|
||||
StructType *t1=expr1->sem_type->structType();
|
||||
StructType *t2=expr2->sem_type->structType();
|
||||
if( !t1 || !t2 ) ex( "Illegal expression type" );
|
||||
if( t1!=t2 ) ex( "Objects types are differnt" );
|
||||
}
|
||||
|
||||
void InsertNode::translate( Codegen *g ){
|
||||
TNode *t1=expr1->translate( g );
|
||||
if( g->debug ) t1=jumpf( t1,"__bbNullObjEx" );
|
||||
TNode *t2=expr2->translate( g );
|
||||
if( g->debug ) t2=jumpf( t2,"__bbNullObjEx" );
|
||||
string s=before ? "__bbObjInsBefore" : "__bbObjInsAfter";
|
||||
g->code( call( s,t1,t2 ) );
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// A select statement //
|
||||
////////////////////////
|
||||
void SelectNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
Type *ty=expr->sem_type;
|
||||
if( ty->structType() ) ex( "Select cannot be used with objects" );
|
||||
|
||||
//we need a temp var
|
||||
Decl *d=e->decls->insertDecl( genLabel(),expr->sem_type,DECL_LOCAL );
|
||||
sem_temp=d_new DeclVarNode( d );
|
||||
|
||||
for( int k=0;k<cases.size();++k ){
|
||||
CaseNode *c=cases[k];
|
||||
c->exprs->semant( e );
|
||||
c->exprs->castTo( ty,e );
|
||||
c->stmts->semant( e );
|
||||
}
|
||||
if( defStmts ) defStmts->semant( e );
|
||||
}
|
||||
|
||||
void SelectNode::translate( Codegen *g ){
|
||||
|
||||
Type *ty=expr->sem_type;
|
||||
|
||||
g->code( sem_temp->store( g,expr->translate( g ) ) );
|
||||
|
||||
vector<string> labs;
|
||||
string brk=genLabel();
|
||||
|
||||
for( int k=0;k<cases.size();++k ){
|
||||
CaseNode *c=cases[k];
|
||||
labs.push_back( genLabel() );
|
||||
for( int j=0;j<c->exprs->size();++j ){
|
||||
ExprNode *e=c->exprs->exprs[j];
|
||||
TNode *t=compare( '=',sem_temp->load( g ),e->translate( g ),ty );
|
||||
g->code( jumpt( t,labs.back() ) );
|
||||
}
|
||||
}
|
||||
if( defStmts ) defStmts->translate( g );
|
||||
g->code( jump( brk ) );
|
||||
for( k=0;k<cases.size();++k ){
|
||||
CaseNode *c=cases[k];
|
||||
g->label( labs[k] );
|
||||
c->stmts->translate( g );
|
||||
g->code( jump( brk ) );
|
||||
}
|
||||
|
||||
g->label( brk );
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// Repeat...Until/Forever //
|
||||
////////////////////////////
|
||||
void RepeatNode::semant( Environ *e ){
|
||||
sem_brk=genLabel();
|
||||
string brk=e->setBreak( sem_brk );
|
||||
stmts->semant( e );
|
||||
e->setBreak( brk );
|
||||
if( expr ){
|
||||
expr=expr->semant( e );
|
||||
expr=expr->castTo( Type::int_type,e );
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatNode::translate( Codegen *g ){
|
||||
|
||||
string loop=genLabel();
|
||||
g->label( loop );
|
||||
stmts->translate( g );
|
||||
debug( untilPos,g );
|
||||
|
||||
if( ConstNode *c=expr ? expr->constNode() : 0 ){
|
||||
if( !c->intValue() ) g->code( jump( loop ) );
|
||||
}else{
|
||||
if( expr ) g->code( jumpf( expr->translate( g ),loop ) );
|
||||
else g->code( jump( loop ) );
|
||||
}
|
||||
g->label( sem_brk );
|
||||
}
|
||||
|
||||
///////////////
|
||||
// Read data //
|
||||
///////////////
|
||||
void ReadNode::semant( Environ *e ){
|
||||
var->semant( e );
|
||||
if( var->sem_type->constType() ) ex( "Constants can not be modified" );
|
||||
if( var->sem_type->structType() ) ex( "Data can not be read into an object" );
|
||||
}
|
||||
|
||||
void ReadNode::translate( Codegen *g ){
|
||||
TNode *t;
|
||||
if( var->sem_type==Type::int_type ) t=call( "__bbReadInt" );
|
||||
else if( var->sem_type==Type::float_type ) t=fcall( "__bbReadFloat" );
|
||||
else t=call( "__bbReadStr" );
|
||||
g->code( var->store( g,t ) );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
|
||||
#ifndef STMTNODE_H
|
||||
#define STMTNODE_H
|
||||
|
||||
#include "node.h"
|
||||
|
||||
struct StmtNode : public Node{
|
||||
int pos; //offset in source stream
|
||||
StmtNode():pos(-1){}
|
||||
void debug( int pos,Codegen *g );
|
||||
|
||||
virtual void semant( Environ *e ){}
|
||||
virtual void translate( Codegen *g ){}
|
||||
};
|
||||
|
||||
struct StmtSeqNode : public Node{
|
||||
string file;
|
||||
vector<StmtNode*> stmts;
|
||||
StmtSeqNode( const string &f ):file(f){}
|
||||
~StmtSeqNode(){ for( ;stmts.size();stmts.pop_back() ) delete stmts.back(); }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
void push_back( StmtNode *s ){ stmts.push_back( s ); }
|
||||
int size(){ return stmts.size(); }
|
||||
|
||||
static void reset( const string &file,const string &lab );
|
||||
};
|
||||
|
||||
#include "exprnode.h"
|
||||
#include "declnode.h"
|
||||
|
||||
struct IncludeNode : public StmtNode{
|
||||
string file,label;
|
||||
StmtSeqNode *stmts;
|
||||
IncludeNode( const string &t,StmtSeqNode *ss ):file(t),stmts(ss){}
|
||||
~IncludeNode(){ delete stmts; }
|
||||
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct DeclStmtNode : public StmtNode{
|
||||
DeclNode *decl;
|
||||
DeclStmtNode( DeclNode *d ):decl(d){ pos=d->pos; }
|
||||
~DeclStmtNode(){ delete decl; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct DimNode : public StmtNode{
|
||||
string ident,tag;
|
||||
ExprSeqNode *exprs;
|
||||
ArrayType *sem_type;
|
||||
Decl *sem_decl;
|
||||
DimNode( const string &i,const string &t,ExprSeqNode *e ):ident(i),tag(t),exprs(e){}
|
||||
~DimNode(){ delete exprs; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct AssNode : public StmtNode{
|
||||
VarNode *var;
|
||||
ExprNode *expr;
|
||||
AssNode( VarNode *var,ExprNode *expr ):var(var),expr(expr){}
|
||||
~AssNode(){ delete var;delete expr; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ExprStmtNode : public StmtNode{
|
||||
ExprNode *expr;
|
||||
ExprStmtNode( ExprNode *e ):expr(e){}
|
||||
~ExprStmtNode(){ delete expr; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct LabelNode : public StmtNode{
|
||||
string ident;
|
||||
int data_sz;
|
||||
LabelNode( const string &s,int sz ):ident(s),data_sz(sz){}
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct GotoNode : public StmtNode{
|
||||
string ident;
|
||||
GotoNode( const string &s ):ident(s){}
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct GosubNode : public StmtNode{
|
||||
string ident;
|
||||
GosubNode( const string &s ):ident(s){}
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct IfNode : public StmtNode{
|
||||
ExprNode *expr;
|
||||
StmtSeqNode *stmts,*elseOpt;
|
||||
IfNode( ExprNode *e,StmtSeqNode *s,StmtSeqNode *o ):expr(e),stmts(s),elseOpt(o){}
|
||||
~IfNode(){ delete expr;delete stmts;delete elseOpt; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ExitNode : public StmtNode{
|
||||
string sem_brk;
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct WhileNode : public StmtNode{
|
||||
int wendPos;
|
||||
ExprNode *expr;
|
||||
StmtSeqNode *stmts;
|
||||
string sem_brk;
|
||||
WhileNode( ExprNode *e,StmtSeqNode *s,int wp ):expr(e),stmts(s),wendPos(wp){}
|
||||
~WhileNode(){ delete expr;delete stmts; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ForNode : public StmtNode{
|
||||
int nextPos;
|
||||
VarNode *var;
|
||||
ExprNode *fromExpr,*toExpr,*stepExpr;
|
||||
StmtSeqNode *stmts;
|
||||
string sem_brk;
|
||||
ForNode( VarNode *v,ExprNode *f,ExprNode *t,ExprNode *s,StmtSeqNode *ss,int np );
|
||||
~ForNode();
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ForEachNode : public StmtNode{
|
||||
int nextPos;
|
||||
VarNode *var;
|
||||
string typeIdent;
|
||||
StmtSeqNode *stmts;
|
||||
string sem_brk;
|
||||
ForEachNode( VarNode *v,const string &t,StmtSeqNode *s,int np):var(v),typeIdent(t),stmts(s),nextPos(np){}
|
||||
~ForEachNode(){ delete var;delete stmts; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ReturnNode : public StmtNode{
|
||||
ExprNode *expr;
|
||||
string returnLabel;
|
||||
ReturnNode( ExprNode *e ):expr( e ){}
|
||||
~ReturnNode(){ delete expr; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct DeleteNode : public StmtNode{
|
||||
ExprNode *expr;
|
||||
DeleteNode( ExprNode *e ):expr(e){}
|
||||
~DeleteNode(){ delete expr; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct DeleteEachNode : public StmtNode{
|
||||
string typeIdent;
|
||||
DeleteEachNode( const string &t ):typeIdent(t){}
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct InsertNode : public StmtNode{
|
||||
ExprNode *expr1,*expr2;
|
||||
bool before;
|
||||
InsertNode( ExprNode *e1,ExprNode *e2,bool b ):expr1(e1),expr2(e2),before(b){}
|
||||
~InsertNode(){ delete expr1;delete expr2; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct CaseNode : public Node{
|
||||
ExprSeqNode *exprs;
|
||||
StmtSeqNode *stmts;
|
||||
CaseNode( ExprSeqNode *e,StmtSeqNode *s ):exprs(e),stmts(s){}
|
||||
~CaseNode(){ delete exprs;delete stmts; }
|
||||
};
|
||||
|
||||
struct SelectNode : public StmtNode{
|
||||
ExprNode *expr;
|
||||
StmtSeqNode *defStmts;
|
||||
vector<CaseNode*> cases;
|
||||
VarNode *sem_temp;
|
||||
SelectNode( ExprNode *e ):expr(e),defStmts(0),sem_temp(0){}
|
||||
~SelectNode(){ delete expr;delete defStmts;delete sem_temp;for( ;cases.size();cases.pop_back() ) delete cases.back(); }
|
||||
void push_back( CaseNode *c ){ cases.push_back( c ); }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct RepeatNode : public StmtNode{
|
||||
int untilPos;
|
||||
StmtSeqNode *stmts;
|
||||
ExprNode *expr;
|
||||
string sem_brk;
|
||||
RepeatNode( StmtSeqNode *s,ExprNode *e,int up ):stmts(s),expr(e),untilPos(up){}
|
||||
~RepeatNode(){ delete stmts;delete expr; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct ReadNode : public StmtNode{
|
||||
VarNode *var;
|
||||
ReadNode( VarNode *v ):var(v){}
|
||||
~ReadNode(){ delete var; }
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct RestoreNode : public StmtNode{
|
||||
string ident;
|
||||
Label *sem_label;
|
||||
RestoreNode( const string &i ):ident(i){}
|
||||
void semant( Environ *e );
|
||||
void translate( Codegen *g );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
struct Node{
|
||||
};
|
||||
|
||||
struct VarNode : public Node{
|
||||
public Type *semant( Environ *e )=0;
|
||||
public TNode *translate( Environ *e )=0;
|
||||
public TNode *evaluate( Environ *e )=0;
|
||||
};
|
||||
|
||||
struct ExprNode : public Node{
|
||||
public Type *semant( Environ *e )=0;
|
||||
public TNode *translate( Environ *e )=0;
|
||||
};
|
||||
|
||||
struct ExprSeqNode : public Node{
|
||||
vector<ExprNode*> exprs;
|
||||
public Type *semant( Environ *e );
|
||||
public TNode *translate( Environ *e );
|
||||
public void push_back( ExprNode *s );
|
||||
public int size();
|
||||
};
|
||||
|
||||
struct StmtNode : public Node{
|
||||
public void semant( Environ *e )=0;
|
||||
public void translate( vector<TNode*> &prog,Environ *e )=0;
|
||||
};
|
||||
|
||||
struct StmtSeqNode : public Node{
|
||||
vector<StmtNode*> stmts;
|
||||
public void semant( Environ *e );
|
||||
public void translate( vector<TNode*> &prog,Environ *e );
|
||||
public void push_back( StmtNode *s );
|
||||
public int size();
|
||||
};
|
||||
|
||||
struct DeclNode : public Node{
|
||||
public void proto( Environ *e )=0;
|
||||
public void semant( Environ *e )=0;
|
||||
public void translate( vector<TNode*> &prog,Environ *e )=0;
|
||||
};
|
||||
|
||||
struct DeclSeqNode : public Node{
|
||||
vector<DeclNode*> decls;
|
||||
public void proto( Environ *e );
|
||||
public void semant( Environ *e );
|
||||
public void translate( vector<TNode*> &prog,Environ *e );
|
||||
public void push_back( DeclNode *d );
|
||||
public int size();
|
||||
};
|
||||
|
||||
struct BlockNode : public Node{
|
||||
DeclSeqNode *decls;
|
||||
StmtSeqNode *stmts;
|
||||
public void proto( Environ *e );
|
||||
public void semant( Environ *e );
|
||||
public void translate( vector<TNode*> &prog,Environ *e );
|
||||
};
|
||||
|
||||
struct ProgNode : public Node{
|
||||
BlockNode *block;
|
||||
public void proto( Environ *e );
|
||||
public void semant( Environ *e );
|
||||
public void translate( Environ *e,Codegen &codegen );
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
|
||||
Notes:
|
||||
|
||||
lexpr is LHS sub-expression.
|
||||
rexpr is RHS sub-expression.
|
||||
iconst is generic int value.
|
||||
sconst is generic string value
|
||||
|
||||
LABEL(sconst)
|
||||
generate code label
|
||||
|
||||
JUMP(sconst)
|
||||
jump to global sconst
|
||||
|
||||
JUMPT(lexpr,sconst)
|
||||
jump to sconst if INT lexpr<>0
|
||||
|
||||
JUMPF(lexpr,sconst)
|
||||
jump to sconst if INT lexpr==0
|
||||
|
||||
JUMPGE(lexpr,rexpr,sconst)
|
||||
jump to sconst if INT lexpr>=INT rexpr
|
||||
|
||||
SEQ(lexpr,rexpr)
|
||||
execute lexpr, rexpr in any order. results not used.
|
||||
|
||||
MOVE(lexpr,rexpr)
|
||||
move lexpr to rexpr. rexpr always a MEM.
|
||||
|
||||
MEM(lexpr)
|
||||
contents of mem in lexpr - except for RHS of MOVE.
|
||||
|
||||
LOCAL(iconst)
|
||||
address of local var at offset iconst
|
||||
|
||||
GLOBAL(sconst)
|
||||
address of global var at sconst
|
||||
|
||||
ARG(iconst)
|
||||
address of argument var at offset iconst
|
||||
|
||||
CONST(iconst)
|
||||
constant
|
||||
|
||||
CALL(lexpr,rexpr,iconst)
|
||||
create argframe of size iconst. eval rexpr and discard result.
|
||||
call address in lexpr. destroy argframe.
|
||||
|
||||
RETURN(lexpr,sconst)
|
||||
eval INT lexpr into int return reg and jump to sconst
|
||||
|
||||
CAST(lexpr)
|
||||
convert FP lexpr to INT.
|
||||
|
||||
NEG,NOT,
|
||||
INT unary expressions. lexpr always int. result int.
|
||||
|
||||
AND,OR,EOR,SHL,SHR,ASR,ADD,SUB,MUL,DIV
|
||||
INT binary expressions. lexpr and rexpr always int. result int.
|
||||
|
||||
SETEQ,SETNE,SETLT,SETGT,SETLE,SETGE
|
||||
INT releational expressions. result '1' if INT lexpr,rexpr comparison
|
||||
true else '0'.
|
||||
|
||||
FCALL
|
||||
like CALL but result is in FP return reg.
|
||||
|
||||
FRETURN(lexpr)
|
||||
like RETURN, but put result into FP return reg. lexpr always FP.
|
||||
|
||||
FCAST(lexpr)
|
||||
convert INT lexpr to FP.
|
||||
|
||||
FNEG
|
||||
FP unary operators. lexpr always FP, result FP.
|
||||
|
||||
FADD,FSUB,FMUL,FDIV,
|
||||
FP binary operators. lexpr, rexpr always FP, result FP
|
||||
|
||||
FSETEQ,FSETNE,FSETLT,FSETGT,FSETLE,FSETGE,
|
||||
FP relational operators. lexpr, rexpr always FP. result INT!
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
* Better source code pos tracker
|
||||
|
||||
All Decls and Stmts should have a 'pos' field.
|
||||
|
||||
* Fix label names - eg: edx no currently allowed as var.
|
||||
|
||||
* Replace Var with Global/Local/Field?
|
||||
|
||||
* No auto-decl of vars on rhs of assignment?
|
||||
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
|
||||
#include "std.h"
|
||||
#include <cctype>
|
||||
#include "toker.h"
|
||||
#include "ex.h"
|
||||
|
||||
int Toker::chars_toked;
|
||||
|
||||
static map<string,int> alphaTokes,lowerTokes;
|
||||
|
||||
static void makeKeywords(){
|
||||
static bool made;
|
||||
if( made ) return;
|
||||
|
||||
alphaTokes["Dim"]=DIM;
|
||||
alphaTokes["Goto"]=GOTO;
|
||||
alphaTokes["Gosub"]=GOSUB;
|
||||
alphaTokes["Return"]=RETURN;
|
||||
alphaTokes["Exit"]=EXIT;
|
||||
alphaTokes["If"]=IF;
|
||||
alphaTokes["Then"]=THEN;
|
||||
alphaTokes["Else"]=ELSE;
|
||||
alphaTokes["EndIf"]=ENDIF;
|
||||
alphaTokes["End If"]=ENDIF;
|
||||
alphaTokes["ElseIf"]=ELSEIF;
|
||||
alphaTokes["Else If"]=ELSEIF;
|
||||
alphaTokes["While"]=WHILE;
|
||||
alphaTokes["Wend"]=WEND;
|
||||
alphaTokes["For"]=FOR;
|
||||
alphaTokes["To"]=TO;
|
||||
alphaTokes["Step"]=STEP;
|
||||
alphaTokes["Next"]=NEXT;
|
||||
alphaTokes["Function"]=FUNCTION;
|
||||
alphaTokes["End Function"]=ENDFUNCTION;
|
||||
alphaTokes["Type"]=TYPE;
|
||||
alphaTokes["End Type"]=ENDTYPE;
|
||||
alphaTokes["Each"]=EACH;
|
||||
alphaTokes["Local"]=LOCAL;
|
||||
alphaTokes["Global"]=GLOBAL;
|
||||
alphaTokes["Field"]=FIELD;
|
||||
alphaTokes["Const"]=BBCONST;
|
||||
alphaTokes["Select"]=SELECT;
|
||||
alphaTokes["Case"]=CASE;
|
||||
alphaTokes["Default"]=DEFAULT;
|
||||
alphaTokes["End Select"]=ENDSELECT;
|
||||
alphaTokes["Repeat"]=REPEAT;
|
||||
alphaTokes["Until"]=UNTIL;
|
||||
alphaTokes["Forever"]=FOREVER;
|
||||
alphaTokes["Data"]=DATA;
|
||||
alphaTokes["Read"]=READ;
|
||||
alphaTokes["Restore"]=RESTORE;
|
||||
alphaTokes["Abs"]=ABS;
|
||||
alphaTokes["Sgn"]=SGN;
|
||||
alphaTokes["Mod"]=MOD;
|
||||
alphaTokes["Pi"]=PI;
|
||||
alphaTokes["True"]=BBTRUE;
|
||||
alphaTokes["False"]=BBFALSE;
|
||||
alphaTokes["Int"]=BBINT;
|
||||
alphaTokes["Float"]=BBFLOAT;
|
||||
alphaTokes["Str"]=BBSTR;
|
||||
alphaTokes["Include"]=INCLUDE;
|
||||
|
||||
alphaTokes["New"]=BBNEW;
|
||||
alphaTokes["Delete"]=BBDELETE;
|
||||
alphaTokes["First"]=FIRST;
|
||||
alphaTokes["Last"]=LAST;
|
||||
alphaTokes["Insert"]=INSERT;
|
||||
alphaTokes["Before"]=BEFORE;
|
||||
alphaTokes["After"]=AFTER;
|
||||
alphaTokes["Null"]=BBNULL;
|
||||
alphaTokes["Object"]=OBJECT;
|
||||
alphaTokes["Handle"]=BBHANDLE;
|
||||
|
||||
alphaTokes["And"]=AND;
|
||||
alphaTokes["Or"]=OR;
|
||||
alphaTokes["Xor"]=XOR;
|
||||
alphaTokes["Not"]=NOT;
|
||||
alphaTokes["Shl"]=SHL;
|
||||
alphaTokes["Shr"]=SHR;
|
||||
alphaTokes["Sar"]=SAR;
|
||||
|
||||
map<string,int>::const_iterator it;
|
||||
for( it=alphaTokes.begin();it!=alphaTokes.end();++it ){
|
||||
lowerTokes[tolower(it->first)]=it->second;
|
||||
}
|
||||
made=true;
|
||||
}
|
||||
|
||||
Toker::Toker( istream &in ):in(in),curr_row(-1){
|
||||
makeKeywords();
|
||||
nextline();
|
||||
}
|
||||
|
||||
map<string,int> &Toker::getKeywords(){
|
||||
makeKeywords();
|
||||
return alphaTokes;
|
||||
}
|
||||
|
||||
int Toker::pos(){
|
||||
return ((curr_row)<<16)|(tokes[curr_toke].from);
|
||||
}
|
||||
|
||||
int Toker::curr(){
|
||||
return tokes[curr_toke].n;
|
||||
}
|
||||
|
||||
string Toker::text(){
|
||||
int from=tokes[curr_toke].from,to=tokes[curr_toke].to;
|
||||
return line.substr( from,to-from );
|
||||
}
|
||||
|
||||
int Toker::lookAhead( int n ){
|
||||
return tokes[curr_toke+n].n;
|
||||
}
|
||||
|
||||
void Toker::nextline(){
|
||||
++curr_row;
|
||||
curr_toke=0;
|
||||
tokes.clear();
|
||||
if( in.eof() ){
|
||||
line.resize(1);line[0]=EOF;
|
||||
tokes.push_back( Toke( EOF,0,1 ) );
|
||||
return;
|
||||
}
|
||||
|
||||
getline( in,line );line+='\n';
|
||||
chars_toked+=line.size();
|
||||
|
||||
for( int k=0;k<line.size(); ){
|
||||
int c=line[k],from=k;
|
||||
if( c=='\n' ){
|
||||
tokes.push_back( Toke( c,from,++k ) );
|
||||
continue;
|
||||
}
|
||||
if( isspace( c ) ){ ++k;continue; }
|
||||
if( c==';' ){
|
||||
for( ++k;line[k]!='\n';++k ){}
|
||||
continue;
|
||||
}
|
||||
if( c=='.' && isdigit( line[k+1] ) ){
|
||||
for( k+=2;isdigit( line[k] );++k ){}
|
||||
tokes.push_back( Toke( FLOATCONST,from,k ) );
|
||||
continue;
|
||||
}
|
||||
if( isdigit( c ) ){
|
||||
for( ++k;isdigit( line[k] );++k ){}
|
||||
if( line[k]=='.' ){
|
||||
for( ++k;isdigit( line[k] );++k ){}
|
||||
tokes.push_back( Toke( FLOATCONST,from,k ) );
|
||||
continue;
|
||||
}
|
||||
tokes.push_back( Toke( INTCONST,from,k ) );
|
||||
continue;
|
||||
}
|
||||
if( c=='%' && (line[k+1]=='0' || line[k+1]=='1') ){
|
||||
for( k+=2;line[k]=='0'||line[k]=='1';++k ){}
|
||||
tokes.push_back( Toke( BINCONST,from,k ) );
|
||||
continue;
|
||||
}
|
||||
if( c=='$' && isxdigit( line[k+1] ) ){
|
||||
for( k+=2;isxdigit( line[k] );++k ){}
|
||||
tokes.push_back( Toke( HEXCONST,from,k ) );
|
||||
continue;
|
||||
}
|
||||
if( isalpha( c ) ){
|
||||
for( ++k;isalnum( line[k] ) || line[k]=='_';++k ){}
|
||||
|
||||
string ident=tolower(line.substr(from,k-from));
|
||||
|
||||
if( line[k]==' ' && isalpha( line[k+1] ) ){
|
||||
int t=k;
|
||||
for( t+=2;isalnum( line[t] ) || line[t]=='_';++t ){}
|
||||
string s=tolower(line.substr(from,t-from));
|
||||
if( lowerTokes.find(s)!=lowerTokes.end() ){
|
||||
k=t;ident=s;
|
||||
}
|
||||
}
|
||||
|
||||
map<string,int>::iterator it=lowerTokes.find( ident );
|
||||
|
||||
if( it==lowerTokes.end() ){
|
||||
for( int n=from;n<k;++n ) line[n]=tolower(line[n]);
|
||||
tokes.push_back( Toke( IDENT,from,k ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
tokes.push_back( Toke( it->second,from,k ) );
|
||||
continue;
|
||||
}
|
||||
if( c=='\"' ){
|
||||
for( ++k;line[k]!='\"' && line[k]!='\n';++k ){}
|
||||
if( line[k]=='\"' ) ++k;
|
||||
tokes.push_back( Toke( STRINGCONST,from,k ) );
|
||||
continue;
|
||||
}
|
||||
int n=line[k+1];
|
||||
if( (c=='<'&&n=='>')||(c=='>'&&n=='<') ){
|
||||
tokes.push_back( Toke( NE,from,k+=2 ) );
|
||||
continue;
|
||||
}
|
||||
if( (c=='<'&&n=='=')||(c=='='&&n=='<') ){
|
||||
tokes.push_back( Toke( LE,from,k+=2 ) );
|
||||
continue;
|
||||
}
|
||||
if( (c=='>'&&n=='=')||(c=='='&&n=='>') ){
|
||||
tokes.push_back( Toke( GE,from,k+=2 ) );
|
||||
continue;
|
||||
}
|
||||
tokes.push_back( Toke( c,from,++k ) );
|
||||
}
|
||||
if( !tokes.size() ) exit(0);
|
||||
}
|
||||
|
||||
int Toker::next(){
|
||||
if( ++curr_toke==tokes.size() ) nextline();
|
||||
return curr();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
/*
|
||||
|
||||
The Toker converts an inout stream into tokens for use by the parser.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TOKER_H
|
||||
#define TOKER_H
|
||||
|
||||
enum{
|
||||
DIM=0x8000,GOTO,GOSUB,EXIT,RETURN,
|
||||
IF,THEN,ELSE,ENDIF,ELSEIF,
|
||||
WHILE,WEND,
|
||||
FOR,TO,STEP,NEXT,
|
||||
FUNCTION,ENDFUNCTION,
|
||||
TYPE,ENDTYPE,EACH,
|
||||
GLOBAL,LOCAL,FIELD,BBCONST,
|
||||
SELECT,CASE,DEFAULT,ENDSELECT,
|
||||
REPEAT,UNTIL,FOREVER,
|
||||
DATA,READ,RESTORE,
|
||||
ABS,SGN,MOD,
|
||||
PI,BBTRUE,BBFALSE,
|
||||
BBINT,BBFLOAT,BBSTR,
|
||||
INCLUDE,
|
||||
|
||||
BBNEW,BBDELETE,FIRST,LAST,INSERT,BEFORE,AFTER,BBNULL,
|
||||
OBJECT,BBHANDLE,
|
||||
AND,OR,XOR,NOT,SHL,SHR,SAR,
|
||||
|
||||
LE,GE,NE,
|
||||
IDENT,INTCONST,BINCONST,HEXCONST,FLOATCONST,STRINGCONST
|
||||
};
|
||||
|
||||
class Toker{
|
||||
public:
|
||||
Toker( istream &in );
|
||||
|
||||
int pos();
|
||||
int curr();
|
||||
int next();
|
||||
string text();
|
||||
int lookAhead( int n );
|
||||
|
||||
static int chars_toked;
|
||||
|
||||
static map<string,int> &getKeywords();
|
||||
|
||||
private:
|
||||
struct Toke{
|
||||
int n,from,to;
|
||||
Toke( int n,int f,int t ):n(n),from(f),to(t){}
|
||||
};
|
||||
istream ∈
|
||||
string line;
|
||||
vector<Toke> tokes;
|
||||
void nextline();
|
||||
int curr_row,curr_toke;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "type.h"
|
||||
|
||||
static struct v_type : public Type{
|
||||
bool canCastTo( Type *t ){
|
||||
return t==Type::void_type;
|
||||
}
|
||||
}v;
|
||||
|
||||
static struct i_type : public Type{
|
||||
bool intType(){
|
||||
return true;
|
||||
}
|
||||
bool canCastTo( Type *t ){
|
||||
return t==Type::int_type || t==Type::float_type || t==Type::string_type;
|
||||
}
|
||||
}i;
|
||||
|
||||
static struct f_type : public Type{
|
||||
bool floatType(){
|
||||
return true;
|
||||
}
|
||||
bool canCastTo( Type *t ){
|
||||
return t==Type::int_type || t==Type::float_type || t==Type::string_type;
|
||||
}
|
||||
}f;
|
||||
|
||||
static struct s_type : public Type{
|
||||
bool stringType(){
|
||||
return true;
|
||||
}
|
||||
bool canCastTo( Type *t ){
|
||||
return t==Type::int_type || t==Type::float_type || t==Type::string_type;
|
||||
}
|
||||
}s;
|
||||
|
||||
bool StructType::canCastTo( Type *t ){
|
||||
return t==this || t==Type::null_type || (this==Type::null_type && t->structType());
|
||||
}
|
||||
|
||||
bool VectorType::canCastTo( Type *t ){
|
||||
if( this==t ) return true;
|
||||
if( VectorType *v=t->vectorType() ){
|
||||
if( elementType!=v->elementType ) return false;
|
||||
if( sizes.size()!=v->sizes.size() ) return false;
|
||||
for( int k=0;k<sizes.size();++k ){
|
||||
if( sizes[k]!=v->sizes[k] ) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static StructType n( "Null" );
|
||||
|
||||
Type *Type::void_type=&v;
|
||||
Type *Type::int_type=&i;
|
||||
Type *Type::float_type=&f;
|
||||
Type *Type::string_type=&s;
|
||||
Type *Type::null_type=&n;
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
#ifndef TYPE_H
|
||||
#define TYPE_H
|
||||
|
||||
#include "decl.h"
|
||||
|
||||
struct FuncType;
|
||||
struct ArrayType;
|
||||
struct StructType;
|
||||
struct ConstType;
|
||||
struct VectorType;
|
||||
|
||||
struct Type{
|
||||
virtual ~Type(){}
|
||||
|
||||
virtual bool intType(){ return 0;}
|
||||
virtual bool floatType(){ return 0; }
|
||||
virtual bool stringType(){ return 0; }
|
||||
|
||||
//casts to inherited types
|
||||
virtual FuncType *funcType(){ return 0; }
|
||||
virtual ArrayType *arrayType(){ return 0; }
|
||||
virtual StructType *structType(){ return 0; }
|
||||
virtual ConstType *constType(){ return 0; }
|
||||
virtual VectorType *vectorType(){ return 0; }
|
||||
|
||||
//operators
|
||||
virtual bool canCastTo( Type *t ){ return this==t; }
|
||||
|
||||
//built in types
|
||||
static Type *void_type,*int_type,*float_type,*string_type,*null_type;
|
||||
};
|
||||
|
||||
struct FuncType : public Type{
|
||||
Type *returnType;
|
||||
DeclSeq *params;
|
||||
bool userlib,cfunc;
|
||||
FuncType( Type *t,DeclSeq *p,bool ulib,bool cfn ):returnType(t),params(p),userlib(ulib),cfunc(cfn){}
|
||||
~FuncType(){ delete params; }
|
||||
FuncType *funcType(){ return this; }
|
||||
};
|
||||
|
||||
struct ArrayType : public Type{
|
||||
Type *elementType;int dims;
|
||||
ArrayType( Type *t,int n ):elementType(t),dims(n){}
|
||||
ArrayType *arrayType(){ return this; }
|
||||
};
|
||||
|
||||
struct StructType : public Type{
|
||||
string ident;
|
||||
DeclSeq *fields;
|
||||
StructType( const string &i ):ident(i),fields(0){}
|
||||
StructType( const string &i,DeclSeq *f ):ident(i),fields( f ){}
|
||||
~StructType(){ delete fields; }
|
||||
StructType *structType(){ return this; }
|
||||
virtual bool canCastTo( Type *t );
|
||||
};
|
||||
|
||||
struct ConstType : public Type{
|
||||
Type *valueType;
|
||||
int intValue;
|
||||
float floatValue;
|
||||
string stringValue;
|
||||
ConstType( int n ):intValue(n),valueType(Type::int_type){}
|
||||
ConstType( float n ):floatValue(n),valueType(Type::float_type){}
|
||||
ConstType( const string &n ):stringValue(n),valueType(Type::string_type){}
|
||||
ConstType *constType(){ return this; }
|
||||
};
|
||||
|
||||
struct VectorType : public Type{
|
||||
string label;
|
||||
Type *elementType;
|
||||
vector<int> sizes;
|
||||
VectorType( const string &l,Type *t,const vector<int> &szs ):label(l),elementType(t),sizes(szs){}
|
||||
VectorType *vectorType(){ return this; }
|
||||
virtual bool canCastTo( Type *t );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
#ifndef VAR_H
|
||||
#define VAR_H
|
||||
|
||||
struct Type;
|
||||
|
||||
struct Var{
|
||||
|
||||
int index;
|
||||
Type *type;
|
||||
|
||||
Var( int i,Type *t ):index(i),type(t){}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,158 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "nodes.h"
|
||||
|
||||
//////////////////////////////////
|
||||
// Common get/set for variables //
|
||||
//////////////////////////////////
|
||||
TNode *VarNode::load( Codegen *g ){
|
||||
TNode *t=translate( g );
|
||||
if( sem_type==Type::string_type ) return call( "__bbStrLoad",t );
|
||||
return mem( t );
|
||||
}
|
||||
|
||||
TNode *VarNode::store( Codegen *g,TNode *n ){
|
||||
TNode *t=translate( g );
|
||||
if( sem_type->structType() ) return call( "__bbObjStore",t,n );
|
||||
if( sem_type==Type::string_type ) return call( "__bbStrStore",t,n );
|
||||
return move( n,mem( t ) );
|
||||
}
|
||||
|
||||
bool VarNode::isObjParam(){
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////
|
||||
// Declared var //
|
||||
//////////////////
|
||||
void DeclVarNode::semant( Environ *e ){
|
||||
}
|
||||
|
||||
TNode *DeclVarNode::translate( Codegen *g ){
|
||||
if( sem_decl->kind==DECL_GLOBAL ) return global( "_v"+sem_decl->name );
|
||||
return local( sem_decl->offset );
|
||||
}
|
||||
|
||||
TNode *DeclVarNode::store( Codegen *g,TNode *n ){
|
||||
if( isObjParam() ){
|
||||
TNode *t=translate( g );
|
||||
return move( n,mem( t ) );
|
||||
}
|
||||
return VarNode::store( g,n );
|
||||
}
|
||||
|
||||
bool DeclVarNode::isObjParam(){
|
||||
return sem_type->structType() && sem_decl->kind==DECL_PARAM;
|
||||
}
|
||||
|
||||
///////////////
|
||||
// Ident var //
|
||||
///////////////
|
||||
void IdentVarNode::semant( Environ *e ){
|
||||
if( sem_decl ) return;
|
||||
Type *t=tagType( tag,e );if( !t ) t=Type::int_type;
|
||||
if( sem_decl=e->findDecl( ident ) ){
|
||||
if( !(sem_decl->kind&(DECL_GLOBAL|DECL_LOCAL|DECL_PARAM)) ){
|
||||
ex( "Identifier '"+sem_decl->name+"' may not be used like this" );
|
||||
}
|
||||
Type *ty=sem_decl->type;
|
||||
if( ty->constType() ) ty=ty->constType()->valueType;
|
||||
if( tag.size() && t!=ty ) ex( "Variable type mismatch" );
|
||||
}else{
|
||||
//ugly auto decl!
|
||||
sem_decl=e->decls->insertDecl( ident,t,DECL_LOCAL );
|
||||
}
|
||||
sem_type=sem_decl->type;
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// Indexed Var //
|
||||
/////////////////
|
||||
void ArrayVarNode::semant( Environ *e ){
|
||||
exprs->semant( e );
|
||||
exprs->castTo( Type::int_type,e );
|
||||
Type *t=e->findType( tag );
|
||||
sem_decl=e->findDecl( ident );
|
||||
if( !sem_decl || !(sem_decl->kind&DECL_ARRAY) ) ex( "Array not found" );
|
||||
ArrayType *a=sem_decl->type->arrayType();
|
||||
if( t && t!=a->elementType ) ex( "array type mismtach" );
|
||||
if( a->dims!=exprs->size() ) ex( "incorrect number of dimensions" );
|
||||
sem_type=a->elementType;
|
||||
}
|
||||
|
||||
TNode *ArrayVarNode::translate( Codegen *g ){
|
||||
TNode *t=0;
|
||||
for( int k=0;k<exprs->size();++k ){
|
||||
TNode *e=exprs->exprs[k]->translate( g );
|
||||
if( k ){
|
||||
TNode *s=mem( add( global( "_a"+ident ),iconst( k*4+8 ) ) );
|
||||
e=add( t,mul( e,s ) );
|
||||
}
|
||||
if( g->debug ){
|
||||
TNode *s=mem( add( global( "_a"+ident ),iconst( k*4+12 ) ) );
|
||||
t=jumpge( e,s,"__bbArrayBoundsEx" );
|
||||
}else t=e;
|
||||
}
|
||||
t=add( mem( global( "_a"+ident ) ),mul( t,iconst( 4 ) ) );
|
||||
return t;
|
||||
}
|
||||
|
||||
///////////////
|
||||
// Field var //
|
||||
///////////////
|
||||
void FieldVarNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
StructType *s=expr->sem_type->structType();
|
||||
if( !s ) ex( "Variable must be a Type" );
|
||||
sem_field=s->fields->findDecl( ident );
|
||||
if( !sem_field ) ex( "Type field not found" );
|
||||
sem_type=sem_field->type;
|
||||
}
|
||||
|
||||
TNode *FieldVarNode::translate( Codegen *g ){
|
||||
TNode *t=expr->translate( g );
|
||||
if( g->debug ) t=jumpf( t,"__bbNullObjEx" );
|
||||
t=mem( t );if( g->debug ) t=jumpf( t,"__bbNullObjEx" );
|
||||
return add( t,iconst( sem_field->offset ) );
|
||||
}
|
||||
|
||||
////////////////
|
||||
// Vector var //
|
||||
////////////////
|
||||
void VectorVarNode::semant( Environ *e ){
|
||||
expr=expr->semant( e );
|
||||
vec_type=expr->sem_type->vectorType();
|
||||
if( !vec_type ) ex( "Variable must be a Blitz array" );
|
||||
if( vec_type->sizes.size()!=exprs->size() ) ex( "Incorrect number of subscripts" );
|
||||
exprs->semant( e );
|
||||
exprs->castTo( Type::int_type,e );
|
||||
for( int k=0;k<exprs->size();++k ){
|
||||
if( ConstNode *t=exprs->exprs[k]->constNode() ){
|
||||
if( t->intValue()>=vec_type->sizes[k] ){
|
||||
ex( "Blitz array subscript out of range" );
|
||||
}
|
||||
}
|
||||
}
|
||||
sem_type=vec_type->elementType;
|
||||
}
|
||||
|
||||
TNode *VectorVarNode::translate( Codegen *g ){
|
||||
int sz=4;
|
||||
TNode *t=0;
|
||||
for( int k=0;k<exprs->size();++k ){
|
||||
TNode *p;
|
||||
ExprNode *e=exprs->exprs[k];
|
||||
if( ConstNode *t=e->constNode() ){
|
||||
p=iconst( t->intValue() * sz );
|
||||
}else{
|
||||
p=e->translate( g );
|
||||
if( g->debug ){
|
||||
p=jumpge( p,iconst( vec_type->sizes[k] ),"__bbVecBoundsEx" );
|
||||
}
|
||||
p=mul( p,iconst( sz ) );
|
||||
}
|
||||
sz=sz*vec_type->sizes[k];
|
||||
t=t ? add( t,p ) : p;
|
||||
}
|
||||
return add( t,expr->translate( g ) );
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
#ifndef VARNODE_H
|
||||
#define VARNODE_H
|
||||
|
||||
#include "varnode.h"
|
||||
|
||||
struct VarNode : public Node{
|
||||
Type *sem_type;
|
||||
|
||||
//get set var
|
||||
TNode *load( Codegen *g );
|
||||
virtual TNode *store( Codegen *g,TNode *n );
|
||||
virtual bool isObjParam();
|
||||
|
||||
//addr of var
|
||||
virtual void semant( Environ *e )=0;
|
||||
virtual TNode *translate( Codegen *g )=0;
|
||||
};
|
||||
|
||||
#include "decl.h"
|
||||
|
||||
struct DeclVarNode : public VarNode{
|
||||
Decl *sem_decl;
|
||||
DeclVarNode( Decl *d=0 ):sem_decl(d){ if( d ) sem_type=d->type; }
|
||||
void semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
virtual TNode *store( Codegen *g,TNode *n );
|
||||
bool isObjParam();
|
||||
};
|
||||
|
||||
struct IdentVarNode : public DeclVarNode{
|
||||
string ident,tag;
|
||||
IdentVarNode( const string &i,const string &t ):ident(i),tag(t){}
|
||||
void semant( Environ *e );
|
||||
};
|
||||
|
||||
struct ArrayVarNode : public VarNode{
|
||||
string ident,tag;
|
||||
ExprSeqNode *exprs;
|
||||
Decl *sem_decl;
|
||||
ArrayVarNode( const string &i,const string &t,ExprSeqNode *e ):ident(i),tag(t),exprs(e){}
|
||||
~ArrayVarNode(){ delete exprs; }
|
||||
void semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct FieldVarNode : public VarNode{
|
||||
ExprNode *expr;
|
||||
string ident,tag;
|
||||
Decl *sem_field;
|
||||
FieldVarNode( ExprNode *e,const string &i,const string &t ):expr(e),ident(i),tag(t){}
|
||||
~FieldVarNode(){ delete expr; }
|
||||
void semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
struct VectorVarNode : public VarNode{
|
||||
ExprNode *expr;
|
||||
ExprSeqNode *exprs;
|
||||
VectorType *vec_type;
|
||||
VectorVarNode( ExprNode *e,ExprSeqNode *es ):expr(e),exprs(es){}
|
||||
~VectorVarNode(){ delete expr;delete exprs; }
|
||||
void semant( Environ *e );
|
||||
TNode *translate( Codegen *g );
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user