Initial commit.

This commit is contained in:
blitz-research
2014-01-31 08:23:00 +13:00
commit 08a613ed0e
322 changed files with 45306 additions and 0 deletions
+15
View File
@@ -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
+585
View File
@@ -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
};
+308
View File
@@ -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 );
}
}
}
+37
View File
@@ -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
+37
View File
@@ -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
+160
View File
@@ -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();
}
+32
View File
@@ -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
+44
View File
@@ -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.
+29
View File
@@ -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
+55
View File
@@ -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
+456
View File
@@ -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;
}
+38
View File
@@ -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 );
};
+273
View File
@@ -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' );
}
+25
View File
@@ -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
View File
+376
View File
@@ -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
View File
+35
View File
@@ -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();
}
+33
View File
@@ -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
+16
View File
@@ -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
+280
View File
@@ -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 );
}
+90
View File
@@ -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
+67
View File
@@ -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;
}
+42
View File
@@ -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
+13
View File
@@ -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
+627
View File
@@ -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 );
}
+193
View File
@@ -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
+38
View File
@@ -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
+13
View File
@@ -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
+284
View File
@@ -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 );
}
+56
View File
@@ -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
+10
View File
@@ -0,0 +1,10 @@
#ifndef NODES_H
#define NODES_H
#include "exprnode.h"
#include "stmtnode.h"
#include "declnode.h"
#include "prognode.h"
#endif
+757
View File
@@ -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;
}
+65
View File
@@ -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
+138
View File
@@ -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();
}
+39
View File
@@ -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
+68
View File
@@ -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;
+53
View File
@@ -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" );
}
}
}
}
+2
View File
@@ -0,0 +1,2 @@
#include "std.h"
+21
View File
@@ -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
+586
View File
@@ -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 ) );
}
+229
View File
@@ -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
View File
View File
+65
View File
@@ -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 );
};
+81
View File
@@ -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!
+12
View File
@@ -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?
+217
View File
@@ -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();
}
+61
View File
@@ -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 &in;
string line;
vector<Toke> tokes;
void nextline();
int curr_row,curr_toke;
};
#endif
+61
View File
@@ -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;
+79
View File
@@ -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
+15
View File
@@ -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
+158
View File
@@ -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 ) );
}
+67
View File
@@ -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