Added first final version of Compiler for VaninVM
This commit is contained in:
parent
095dafa97d
commit
c2219325c9
8 changed files with 1549 additions and 0 deletions
456
CompilerVVM/ByteCode.cs
Normal file
456
CompilerVVM/ByteCode.cs
Normal file
|
@ -0,0 +1,456 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CompilerVVM
|
||||||
|
{
|
||||||
|
class pair
|
||||||
|
{
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
public pair(int one, int two)
|
||||||
|
{
|
||||||
|
start = one;
|
||||||
|
end = two;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class str_header
|
||||||
|
{
|
||||||
|
public byte[] signature
|
||||||
|
{ get; set; }
|
||||||
|
public int version
|
||||||
|
{ get; set; }
|
||||||
|
public int const_count
|
||||||
|
{ get; set; }
|
||||||
|
public int size_const
|
||||||
|
{ get; set; }
|
||||||
|
|
||||||
|
public str_header()
|
||||||
|
{
|
||||||
|
signature = new byte[2];
|
||||||
|
signature[0] = 0xBA;
|
||||||
|
signature[1] = 0xBA;
|
||||||
|
version = 0100;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream m = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(m))
|
||||||
|
{
|
||||||
|
writer.Write(signature);
|
||||||
|
writer.Write(version);
|
||||||
|
writer.Write(const_count);
|
||||||
|
writer.Write(size_const);
|
||||||
|
}
|
||||||
|
return m.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class funcH_common
|
||||||
|
{
|
||||||
|
public ushort start_id
|
||||||
|
{ get; set; }
|
||||||
|
public int count_of_funcs
|
||||||
|
{ get; set; }
|
||||||
|
|
||||||
|
public funcH_common(ushort id, int count)
|
||||||
|
{
|
||||||
|
start_id = id;
|
||||||
|
count_of_funcs = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream m = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(m))
|
||||||
|
{
|
||||||
|
writer.Write(start_id);
|
||||||
|
writer.Write(count_of_funcs);
|
||||||
|
|
||||||
|
}
|
||||||
|
return m.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class funcH_signature
|
||||||
|
{
|
||||||
|
public int size_func
|
||||||
|
{ get; set; }
|
||||||
|
public int size_bytecode
|
||||||
|
{ get; set; }
|
||||||
|
public int size_signature
|
||||||
|
{ get; set; }
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream m = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(m))
|
||||||
|
{
|
||||||
|
writer.Write(size_func);
|
||||||
|
writer.Write(size_bytecode);
|
||||||
|
writer.Write(size_signature);
|
||||||
|
}
|
||||||
|
return m.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class funcH_bytecode
|
||||||
|
{
|
||||||
|
public ushort id
|
||||||
|
{ get; set; }
|
||||||
|
public int count_locals
|
||||||
|
{ get; set; }
|
||||||
|
public int count_args
|
||||||
|
{ get; set; }
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream m = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(m))
|
||||||
|
{
|
||||||
|
writer.Write(id);
|
||||||
|
writer.Write(count_locals);
|
||||||
|
writer.Write(count_args);
|
||||||
|
}
|
||||||
|
return m.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public funcH_bytecode()
|
||||||
|
{
|
||||||
|
count_locals = 0;
|
||||||
|
count_args = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ByteCode
|
||||||
|
{
|
||||||
|
public static void GenerateByteCode(string[] code, string outname)
|
||||||
|
{
|
||||||
|
Dictionary<int, string> ConstID_VALUE = new Dictionary<int, string>();
|
||||||
|
Dictionary<string, int> ConstKEY_ID = new Dictionary<string, int>();
|
||||||
|
Dictionary<string, int> CodeMARK_POS = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
List<pair> FuncPos = new List<pair>();
|
||||||
|
|
||||||
|
int[] pos_d = new int[2] { 0, 0 };
|
||||||
|
string[] source = code;
|
||||||
|
List<string> src = PositionAnalyse(source, ref pos_d, ref FuncPos, ref CodeMARK_POS);
|
||||||
|
|
||||||
|
|
||||||
|
using (var bw = new BinaryWriter(File.Open(outname, FileMode.OpenOrCreate)))
|
||||||
|
{
|
||||||
|
|
||||||
|
HeaderAnalyse(src, pos_d, bw, ref ConstID_VALUE, ref ConstKEY_ID);
|
||||||
|
funcH_common FuncCommonH = new funcH_common(CRC16_alg("main"), FuncPos.Count);
|
||||||
|
bw.Write(FuncCommonH.Serialize());
|
||||||
|
for (int i = 0; i < FuncPos.Count; i++)
|
||||||
|
{
|
||||||
|
FuncAnalyse(src, FuncPos[i], bw, ConstKEY_ID, CodeMARK_POS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> PositionAnalyse(string[] input, ref int[] posD, ref List<pair> posC, ref Dictionary<string, int> marks)
|
||||||
|
{
|
||||||
|
List<string> src = new List<string>();
|
||||||
|
bool func_flag = false;
|
||||||
|
int pos1 = 0, pos2 = 0, numline = 0;
|
||||||
|
foreach (string s in input)
|
||||||
|
if (s != "")
|
||||||
|
{
|
||||||
|
if (func_flag == true && Regex.IsMatch(s, @"\w+:"))
|
||||||
|
{
|
||||||
|
marks.Add(s.Trim(' ', '\t', ':'), numline);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
src.Add(s.Trim(' ', '\t'));
|
||||||
|
|
||||||
|
if (s.Contains(".data"))
|
||||||
|
posD[0] = src.Count - 1;
|
||||||
|
if (s.Contains(".endd"))
|
||||||
|
posD[1] = src.Count - 1;
|
||||||
|
|
||||||
|
if (s.Contains(".proc"))
|
||||||
|
{
|
||||||
|
numline = 0;
|
||||||
|
pos1 = src.Count - 1;
|
||||||
|
func_flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.Contains(".endp"))
|
||||||
|
{
|
||||||
|
pos2 = src.Count - 1;
|
||||||
|
if (func_flag == true)
|
||||||
|
{
|
||||||
|
func_flag = false;
|
||||||
|
posC.Add(new pair(pos1, pos2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numline++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
private static void HeaderAnalyse(List<string> src, int[] pos, BinaryWriter bw, ref Dictionary<int, string> id_v, ref Dictionary<string, int> k_id)
|
||||||
|
{
|
||||||
|
str_header ConstH = new str_header();
|
||||||
|
string pattern = "\".*\"";
|
||||||
|
int j = 1;
|
||||||
|
for (int i = pos[0] + 1; i < pos[1]; i++)
|
||||||
|
{
|
||||||
|
int position = src[i].IndexOf(" ");
|
||||||
|
string key = src[i].Substring(0, position);
|
||||||
|
string value = Regex.Match(src[i], pattern).ToString().Trim('"').Replace(@"\n", "\n").Replace(@"\r", "\r") + "\0";
|
||||||
|
id_v.Add(j, value); k_id.Add(key, j++);
|
||||||
|
ConstH.const_count++; ConstH.size_const += (value.Length);
|
||||||
|
}
|
||||||
|
bw.Write(ConstH.Serialize());
|
||||||
|
for (int i = 1; i < j; i++)
|
||||||
|
{
|
||||||
|
bw.Write(Encoding.ASCII.GetBytes(id_v[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void FuncAnalyse(List<string> code, pair pos, BinaryWriter bw, Dictionary<string, int> dictStr, Dictionary<string, int> dictJmp)
|
||||||
|
{
|
||||||
|
string name = "";
|
||||||
|
MemoryStream str = new MemoryStream();
|
||||||
|
funcH_signature sign = new funcH_signature();
|
||||||
|
funcH_bytecode bc = new funcH_bytecode();
|
||||||
|
|
||||||
|
|
||||||
|
string[] current_str = code[pos.start].Split(' ');
|
||||||
|
switch (current_str.Length)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
bc.count_args = System.Convert.ToInt32(current_str[3]);
|
||||||
|
bc.count_locals = System.Convert.ToInt32(current_str[2]);
|
||||||
|
name = current_str[1];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
bc.count_locals = System.Convert.ToInt32(current_str[2]);
|
||||||
|
name = current_str[1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
name = current_str[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bc.id = CRC16_alg(name);
|
||||||
|
name += "\0";
|
||||||
|
sign.size_signature = name.Length;
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(str))
|
||||||
|
{
|
||||||
|
int j = 1;
|
||||||
|
for (int i = pos.start + 1; i < pos.end; i++)
|
||||||
|
{
|
||||||
|
current_str = code[i].Split(' ');
|
||||||
|
opcode current_opc = (opcode)Enum.Parse(typeof(opcode), current_str[0].ToUpper());
|
||||||
|
writer.Write((byte)current_opc);
|
||||||
|
|
||||||
|
if (current_opc == opcode.DLOAD)
|
||||||
|
writer.Write(Convert.ToDouble(current_str[1]));
|
||||||
|
else if (current_opc == opcode.ILOAD)
|
||||||
|
writer.Write(Convert.ToInt64(current_str[1]));
|
||||||
|
else if (current_opc == opcode.SLOAD)
|
||||||
|
writer.Write((ushort)dictStr[current_str[1]]);
|
||||||
|
else if (current_opc == opcode.CALL)
|
||||||
|
writer.Write(CRC16_alg(current_str[1]));
|
||||||
|
else if (threebytes.Contains(current_opc))
|
||||||
|
writer.Write(ushort.Parse(current_str[1]));
|
||||||
|
else if (fivebytes.Contains(current_opc))
|
||||||
|
{
|
||||||
|
writer.Write(CRC16_alg(current_str[1]));
|
||||||
|
writer.Write(ushort.Parse(current_str[2]));
|
||||||
|
}
|
||||||
|
else if (jumps.Contains(current_opc))
|
||||||
|
writer.Write(FindOffset(code, pos, j, ((ushort)dictJmp[current_str[1]] - j)));
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] bcode = str.ToArray();
|
||||||
|
sign.size_bytecode = bcode.Length;
|
||||||
|
sign.size_func = 22 + sign.size_bytecode + sign.size_signature;
|
||||||
|
|
||||||
|
bw.Write(sign.Serialize());
|
||||||
|
bw.Write(Encoding.ASCII.GetBytes(name));
|
||||||
|
bw.Write(bc.Serialize());
|
||||||
|
bw.Write(bcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static short FindOffset(List<string> code, pair pos, int curr_pos, int off)
|
||||||
|
{
|
||||||
|
short result = 0;
|
||||||
|
if (off > 0)
|
||||||
|
{
|
||||||
|
for (int i = curr_pos + 1; i < curr_pos + off; i++)
|
||||||
|
{
|
||||||
|
result += OpCodeSize((opcode)Enum.Parse(typeof(opcode), code[pos.start + i].Split(' ')[0].ToUpper()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = curr_pos; i >= curr_pos + off; i--)
|
||||||
|
{
|
||||||
|
result -= OpCodeSize((opcode)Enum.Parse(typeof(opcode), code[pos.start + i].Split(' ')[0].ToUpper()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static short OpCodeSize(opcode opc)
|
||||||
|
{
|
||||||
|
short result = 0;
|
||||||
|
if (jumps.Contains(opc) || threebytes.Contains(opc))
|
||||||
|
result += 3;
|
||||||
|
else if (fivebytes.Contains(opc))
|
||||||
|
result += 5;
|
||||||
|
else if (ninebytes.Contains(opc))
|
||||||
|
result += 9;
|
||||||
|
else result++;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ushort CRC16_alg(string msg)
|
||||||
|
{
|
||||||
|
byte[] text = Encoding.ASCII.GetBytes(msg);
|
||||||
|
const ushort polinom = 0xa001;
|
||||||
|
ushort code = 0xffff;
|
||||||
|
|
||||||
|
for (int i = 0, size = text.Length; i < size; ++i)
|
||||||
|
{
|
||||||
|
code ^= (ushort)(text[i] << 8);
|
||||||
|
|
||||||
|
for (uint j = 0; j < 8; ++j)
|
||||||
|
{
|
||||||
|
code >>= 1;
|
||||||
|
if ((code & 0x01) != 0) code ^= polinom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static List<opcode> onebyte = new List<opcode>{opcode.INVALID, opcode.DLOAD0, opcode.ILOAD0, opcode.SLOAD0, opcode.DLOAD1, opcode.ILOAD1, opcode.DLOADM1,
|
||||||
|
opcode.ILOADM1, opcode.DADD, opcode.IADD, opcode.DSUB, opcode.ISUB, opcode.DMUL, opcode.IMUL, opcode.DDIV, opcode.IDIV, opcode.IMOD, opcode.DNEG,
|
||||||
|
opcode.INEG, opcode.IAOR, opcode.IAAND, opcode.IAXOR, opcode.IPRINT, opcode.DPRINT, opcode.SPRINT, opcode.I2D, opcode.D2I, opcode.S2I, opcode.SWAP,
|
||||||
|
opcode.POP, opcode.LOADDVAR0, opcode.LOADDVAR1, opcode.LOADDVAR2, opcode.LOADDVAR3, opcode.LOADIVAR0, opcode.LOADIVAR1, opcode.LOADIVAR2, opcode.LOADIVAR3,
|
||||||
|
opcode.LOADSVAR0, opcode.LOADSVAR1, opcode.LOADSVAR2, opcode.LOADSVAR3, opcode.STOREDVAR0, opcode.STOREDVAR1, opcode.STOREDVAR2, opcode.STOREDVAR3,
|
||||||
|
opcode.STOREIVAR0, opcode.STOREIVAR1, opcode.STOREIVAR2, opcode.STOREIVAR3, opcode.STORESVAR0, opcode.STORESVAR1, opcode.STORESVAR2, opcode.STORESVAR3,
|
||||||
|
opcode.ICMP, opcode.DCMP, opcode.DUMP, opcode.STOP, opcode.RETURN, opcode.BREAK};*/
|
||||||
|
|
||||||
|
static List<opcode> ninebytes = new List<opcode> { opcode.DLOAD, opcode.ILOAD };
|
||||||
|
|
||||||
|
static List<opcode> threebytes = new List<opcode> { opcode.LOADDVAR, opcode.LOADIVAR, opcode.LOADSVAR, opcode.STOREDVAR,
|
||||||
|
opcode.STOREIVAR, opcode.STORESVAR, opcode.SLOAD, opcode.CALL};
|
||||||
|
|
||||||
|
static List<opcode> fivebytes = new List<opcode> {opcode.LOADCTXDVAR, opcode.LOADCTXIVAR, opcode.LOADCTXSVAR, opcode.STORECTXDVAR,
|
||||||
|
opcode.STORECTXIVAR, opcode.STORECTXSVAR};
|
||||||
|
|
||||||
|
static List<opcode> jumps = new List<opcode> {opcode.JA, opcode.IFICMPE, opcode.IFICMPG, opcode.IFICMPGE, opcode.IFICMPL,
|
||||||
|
opcode.IFICMPLE, opcode.IFICMPNE};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum opcode
|
||||||
|
{
|
||||||
|
INVALID,
|
||||||
|
DLOAD,
|
||||||
|
ILOAD,
|
||||||
|
SLOAD,
|
||||||
|
DLOAD0,
|
||||||
|
ILOAD0,
|
||||||
|
SLOAD0,
|
||||||
|
DLOAD1,
|
||||||
|
ILOAD1,
|
||||||
|
DLOADM1,
|
||||||
|
ILOADM1,
|
||||||
|
DADD,
|
||||||
|
IADD,
|
||||||
|
DSUB,
|
||||||
|
ISUB,
|
||||||
|
DMUL,
|
||||||
|
IMUL,
|
||||||
|
DDIV,
|
||||||
|
IDIV,
|
||||||
|
IMOD,
|
||||||
|
DNEG,
|
||||||
|
INEG,
|
||||||
|
IAOR,
|
||||||
|
IAAND,
|
||||||
|
IAXOR,
|
||||||
|
IPRINT,
|
||||||
|
DPRINT,
|
||||||
|
SPRINT,
|
||||||
|
I2D,
|
||||||
|
D2I,
|
||||||
|
S2I,
|
||||||
|
SWAP,
|
||||||
|
POP,
|
||||||
|
LOADDVAR0,
|
||||||
|
LOADDVAR1,
|
||||||
|
LOADDVAR2,
|
||||||
|
LOADDVAR3,
|
||||||
|
LOADIVAR0,
|
||||||
|
LOADIVAR1,
|
||||||
|
LOADIVAR2,
|
||||||
|
LOADIVAR3,
|
||||||
|
LOADSVAR0,
|
||||||
|
LOADSVAR1,
|
||||||
|
LOADSVAR2,
|
||||||
|
LOADSVAR3,
|
||||||
|
STOREDVAR0,
|
||||||
|
STOREDVAR1,
|
||||||
|
STOREDVAR2,
|
||||||
|
STOREDVAR3,
|
||||||
|
STOREIVAR0,
|
||||||
|
STOREIVAR1,
|
||||||
|
STOREIVAR2,
|
||||||
|
STOREIVAR3,
|
||||||
|
STORESVAR0,
|
||||||
|
STORESVAR1,
|
||||||
|
STORESVAR2,
|
||||||
|
STORESVAR3,
|
||||||
|
LOADDVAR,
|
||||||
|
LOADIVAR,
|
||||||
|
LOADSVAR,
|
||||||
|
STOREDVAR,
|
||||||
|
STOREIVAR,
|
||||||
|
STORESVAR,
|
||||||
|
LOADCTXDVAR,
|
||||||
|
LOADCTXIVAR,
|
||||||
|
LOADCTXSVAR,
|
||||||
|
STORECTXDVAR,
|
||||||
|
STORECTXIVAR,
|
||||||
|
STORECTXSVAR,
|
||||||
|
DCMP,
|
||||||
|
ICMP,
|
||||||
|
JA,
|
||||||
|
IFICMPNE,
|
||||||
|
IFICMPE,
|
||||||
|
IFICMPG,
|
||||||
|
IFICMPGE,
|
||||||
|
IFICMPL,
|
||||||
|
IFICMPLE,
|
||||||
|
DUMP,
|
||||||
|
STOP,
|
||||||
|
CALL,
|
||||||
|
RETURN,
|
||||||
|
BREAK
|
||||||
|
};
|
||||||
|
}
|
68
CompilerVVM/CodeGen.cs
Normal file
68
CompilerVVM/CodeGen.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CompilerVVM
|
||||||
|
{
|
||||||
|
class CodeGen
|
||||||
|
{
|
||||||
|
Dictionary<string, string> ConstData;
|
||||||
|
Dictionary<string, MethodAtom> Methods;
|
||||||
|
public string[] asm { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public CodeGen(Dictionary<string, string> ConstData, Dictionary<string, MethodAtom> Methods)
|
||||||
|
{
|
||||||
|
this.ConstData = ConstData;
|
||||||
|
this.Methods = Methods;
|
||||||
|
asm = null;
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, MethodAtom> p in Methods)
|
||||||
|
{
|
||||||
|
Optimization(p.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FillAsmCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FillAsmCode()
|
||||||
|
{
|
||||||
|
List<string> Code = new List<string>();
|
||||||
|
if (ConstData.Count > 0)
|
||||||
|
{
|
||||||
|
Code.Add(".data");
|
||||||
|
foreach (KeyValuePair<string, string> pair in ConstData)
|
||||||
|
{
|
||||||
|
Code.Add(string.Format("{0} \"{1}\"", pair.Value, pair.Key));
|
||||||
|
}
|
||||||
|
Code.Add(".endd");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, MethodAtom> entry in Methods)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < entry.Value.Code.Count; i++)
|
||||||
|
Code.Add(entry.Value.Code[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
asm = Code.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Optimization(MethodAtom Method)
|
||||||
|
{
|
||||||
|
List<string> OptimizationSub = new List<string>(){"LOADDVAR", "LOADIVAR", "LOADSVAR", "STOREDVAR", "STOREIVAR",
|
||||||
|
"STORESVAR"};
|
||||||
|
|
||||||
|
for (int i = 0; i < Method.Code.Count; i++ )
|
||||||
|
{
|
||||||
|
string[] parts = Method.Code[i].Split(' ');
|
||||||
|
if (OptimizationSub.Contains(parts[0]) && int.Parse(parts[1]) < 4)
|
||||||
|
{
|
||||||
|
Method.Code[i] = Method.Code[i].Replace(" ", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
CompilerVVM/CustomExceptions.cs
Normal file
35
CompilerVVM/CustomExceptions.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CompilerVVM
|
||||||
|
{
|
||||||
|
public class ScannerException : Exception
|
||||||
|
{
|
||||||
|
public ScannerException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProcedureException : Exception
|
||||||
|
{
|
||||||
|
public ProcedureException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParserException : Exception
|
||||||
|
{
|
||||||
|
public ParserException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
558
CompilerVVM/Parser.cs
Normal file
558
CompilerVVM/Parser.cs
Normal file
|
@ -0,0 +1,558 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CompilerVVM
|
||||||
|
{
|
||||||
|
public class Parser
|
||||||
|
{
|
||||||
|
int pointer;
|
||||||
|
IList<object> Tokens;
|
||||||
|
int idvar;
|
||||||
|
Dictionary<string, string> Constants;
|
||||||
|
Dictionary<string, MethodAtom> Methods;
|
||||||
|
int jumpid;
|
||||||
|
|
||||||
|
public Parser(IList<object> tokens, Dictionary<string, string> TextConst, Dictionary<string, MethodAtom> Methods)
|
||||||
|
{
|
||||||
|
Tokens = tokens;
|
||||||
|
pointer = 0;
|
||||||
|
jumpid = 0;
|
||||||
|
Constants = TextConst;
|
||||||
|
this.Methods = Methods;
|
||||||
|
ParseMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseMethod()
|
||||||
|
{
|
||||||
|
//<program> := <method>+
|
||||||
|
while (pointer != Tokens.Count)
|
||||||
|
{
|
||||||
|
//<method> := method <type_method> <ident>(<param>*) <block>
|
||||||
|
//<type> := int | double | string
|
||||||
|
//<type_method> := <type> | void
|
||||||
|
MethodAtom method = null;
|
||||||
|
if (!Tokens[pointer++].Equals("method"))
|
||||||
|
throw new ParserException("No method detected");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
method = Methods[Tokens[++pointer].ToString()];
|
||||||
|
idvar = method.NumOfParams;
|
||||||
|
method.Code.Add(String.Format(".proc {0}", method.Name, method.NumOfParams));
|
||||||
|
|
||||||
|
pointer += 3 + (2 * method.NumOfParams);
|
||||||
|
if (Tokens[pointer].Equals(OP.OpenBlock))
|
||||||
|
{
|
||||||
|
pointer++;
|
||||||
|
ParseBlock(method);
|
||||||
|
}
|
||||||
|
else throw new ParserException("No code block in method: " + method.Name);
|
||||||
|
|
||||||
|
if (method.Name == "main")
|
||||||
|
method.Code.Add("STOP");
|
||||||
|
else if (method.Type == "void")
|
||||||
|
method.Code.Add("RETURN");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (method.Code[method.Code.Count - 1] != "RETURN")
|
||||||
|
throw new ParserException("No return sequence in method:" + method.Name);
|
||||||
|
}
|
||||||
|
method.Code.Add(".endp");
|
||||||
|
|
||||||
|
method.NumOfLocals = method.Variables.Count;
|
||||||
|
method.Code[0] = String.Format(".proc {0} {1} {2}", method.Name, method.NumOfLocals, method.NumOfParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseBlock(MethodAtom method)
|
||||||
|
{
|
||||||
|
while (!Tokens[pointer].Equals(OP.CloseBlock))
|
||||||
|
{
|
||||||
|
if (Tokens[pointer].Equals(OP.Semicolon))
|
||||||
|
{
|
||||||
|
pointer++;
|
||||||
|
}
|
||||||
|
else if (code_types.Contains(Tokens[pointer].ToString()))
|
||||||
|
DeclareVar(method);
|
||||||
|
else if (Tokens[pointer + 1].Equals(OP.Assigment))
|
||||||
|
{
|
||||||
|
List<Variable> NeededVars = method.Variables.FindAll(x => x.Name == Tokens[pointer].ToString());
|
||||||
|
if (NeededVars.Count == 0)
|
||||||
|
throw new ParserException(string.Format("Variable {0} is not defined", Tokens[pointer].ToString()));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pointer += 2;
|
||||||
|
ParseExpression(method, NeededVars[NeededVars.Count - 1].Type);
|
||||||
|
switch (NeededVars[NeededVars.Count - 1].Type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add(string.Format("STOREIVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
||||||
|
break;
|
||||||
|
case "double":
|
||||||
|
method.Code.Add(string.Format("STOREDVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
||||||
|
break;
|
||||||
|
case "string":
|
||||||
|
method.Code.Add(string.Format("STORESVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer].ToString() == "return")
|
||||||
|
{
|
||||||
|
ParseSingleExpr(method, pointer + 1, method.Type);
|
||||||
|
method.Code.Add("RETURN");
|
||||||
|
pointer += 3;
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer].ToString() == "if")
|
||||||
|
{
|
||||||
|
if (!Tokens[pointer + 1].Equals(OP.OpenParam) || !Tokens[pointer + 5].Equals(OP.CloseParam))
|
||||||
|
throw new ParserException("Wrong if statement");
|
||||||
|
string var1 = GetTypeOfVar(method, pointer + 2);
|
||||||
|
string var2 = GetTypeOfVar(method, pointer + 4);
|
||||||
|
if (var1 != var2)
|
||||||
|
throw new ParserException("Incompatible variable types in if statement");
|
||||||
|
int jump = jumpid++;
|
||||||
|
ParseSingleExpr(method, pointer + 4, var2);
|
||||||
|
ParseSingleExpr(method, pointer + 2, var1);
|
||||||
|
|
||||||
|
switch ((OP)Tokens[pointer + 3])
|
||||||
|
{
|
||||||
|
case OP.Equal:
|
||||||
|
method.Code.Add(string.Format("IFICMPNE jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.NotEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPE jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.Greater:
|
||||||
|
method.Code.Add(string.Format("IFICMPLE jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.GreaterEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPL jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.Less:
|
||||||
|
method.Code.Add(string.Format("IFICMPGE jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.LessEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPG jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
method.Code.Add("POP");
|
||||||
|
method.Code.Add("POP");
|
||||||
|
if (!Tokens[pointer + 6].Equals(OP.OpenBlock))
|
||||||
|
throw new ParserException("No { code } in if statement");
|
||||||
|
pointer += 7;
|
||||||
|
ParseBlock(method);
|
||||||
|
if (Tokens[pointer].ToString() != "else")
|
||||||
|
{
|
||||||
|
method.Code.Add(string.Format("jump_{0}:", jump));
|
||||||
|
method.Code.Add("POP");
|
||||||
|
method.Code.Add("POP");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int jump2 = jumpid++;
|
||||||
|
method.Code.Add(string.Format("JA jump_{0}", jump2));
|
||||||
|
if (!Tokens[pointer + 1].Equals(OP.OpenBlock))
|
||||||
|
throw new ParserException("No { code } in else statement");
|
||||||
|
method.Code.Add(string.Format("jump_{0}:", jump));
|
||||||
|
method.Code.Add("POP");
|
||||||
|
method.Code.Add("POP");
|
||||||
|
pointer += 2;
|
||||||
|
ParseBlock(method);
|
||||||
|
method.Code.Add(string.Format("jump_{0}:", jump2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer].ToString() == "while")
|
||||||
|
{
|
||||||
|
if (!Tokens[pointer + 1].Equals(OP.OpenParam) || !Tokens[pointer + 5].Equals(OP.CloseParam))
|
||||||
|
throw new ParserException("Wrong while statement");
|
||||||
|
string var1 = GetTypeOfVar(method, pointer + 2);
|
||||||
|
string var2 = GetTypeOfVar(method, pointer + 4);
|
||||||
|
if (var1 != var2)
|
||||||
|
throw new ParserException("Incompatible variable types in while statement");
|
||||||
|
int jump = jumpid++;
|
||||||
|
int jump2 = jumpid++;
|
||||||
|
|
||||||
|
method.Code.Add(string.Format("jump_{0}:", jump));
|
||||||
|
ParseSingleExpr(method, pointer + 4, var2);
|
||||||
|
ParseSingleExpr(method, pointer + 2, var1);
|
||||||
|
|
||||||
|
switch ((OP)Tokens[pointer + 3])
|
||||||
|
{
|
||||||
|
case OP.Equal:
|
||||||
|
method.Code.Add(string.Format("IFICMPNE jump_{0}", jump2));
|
||||||
|
break;
|
||||||
|
case OP.NotEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPE jump_{0}", jump2));
|
||||||
|
break;
|
||||||
|
case OP.Greater:
|
||||||
|
method.Code.Add(string.Format("IFICMPLE jump_{0}", jump2));
|
||||||
|
break;
|
||||||
|
case OP.GreaterEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPL jump_{0}", jump2));
|
||||||
|
break;
|
||||||
|
case OP.Less:
|
||||||
|
method.Code.Add(string.Format("IFICMPGE jump_{0}", jump2));
|
||||||
|
break;
|
||||||
|
case OP.LessEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPG jump_{0}", jump2));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
method.Code.Add("POP");
|
||||||
|
method.Code.Add("POP");
|
||||||
|
if (!Tokens[pointer + 6].Equals(OP.OpenBlock))
|
||||||
|
throw new ParserException("No { code } in while statement");
|
||||||
|
pointer += 7;
|
||||||
|
ParseBlock(method);
|
||||||
|
method.Code.Add(string.Format("JA jump_{0}", jump));
|
||||||
|
method.Code.Add(string.Format("jump_{0}:", jump2));
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer].ToString() == "do")
|
||||||
|
{
|
||||||
|
int jump = jumpid++;
|
||||||
|
int jump2 = jumpid++;
|
||||||
|
method.Code.Add(string.Format("JA jump_{0}", jump2));
|
||||||
|
method.Code.Add(string.Format("jump_{0}:", jump));
|
||||||
|
method.Code.Add("POP");
|
||||||
|
method.Code.Add("POP");
|
||||||
|
method.Code.Add(string.Format("jump_{0}:", jump2));
|
||||||
|
pointer += 2;
|
||||||
|
ParseBlock(method);
|
||||||
|
|
||||||
|
if (!Tokens[pointer + 1].Equals(OP.OpenParam) || !Tokens[pointer + 5].Equals(OP.CloseParam) ||
|
||||||
|
Tokens[pointer].ToString() != "until")
|
||||||
|
throw new ParserException("Wrong until statement");
|
||||||
|
string var1 = GetTypeOfVar(method, pointer + 2);
|
||||||
|
string var2 = GetTypeOfVar(method, pointer + 4);
|
||||||
|
if (var1 != var2)
|
||||||
|
throw new Exception("Incompatible variable types in until statement");
|
||||||
|
|
||||||
|
ParseSingleExpr(method, pointer + 4, var2);
|
||||||
|
ParseSingleExpr(method, pointer + 2, var1);
|
||||||
|
|
||||||
|
switch ((OP)Tokens[pointer + 3])
|
||||||
|
{
|
||||||
|
case OP.Equal:
|
||||||
|
method.Code.Add(string.Format("IFICMPNE jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.NotEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPE jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.Greater:
|
||||||
|
method.Code.Add(string.Format("IFICMPLE jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.GreaterEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPL jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.Less:
|
||||||
|
method.Code.Add(string.Format("IFICMPGE jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
case OP.LessEqual:
|
||||||
|
method.Code.Add(string.Format("IFICMPG jump_{0}", jump));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
method.Code.Add("POP");
|
||||||
|
method.Code.Add("POP");
|
||||||
|
pointer += 7;
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer].ToString() == "print")
|
||||||
|
{
|
||||||
|
pointer += 2;
|
||||||
|
string type = GetTypeOfVar(method, pointer);
|
||||||
|
ParseSingleExpr(method, pointer, type);
|
||||||
|
pointer += 3;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add("IPRINT");
|
||||||
|
break;
|
||||||
|
case "double":
|
||||||
|
method.Code.Add("DPRINT");
|
||||||
|
break;
|
||||||
|
case "string":
|
||||||
|
method.Code.Add("SPRINT");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer+1].Equals(OP.OpenParam))
|
||||||
|
{
|
||||||
|
ParseCall(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pointer++;
|
||||||
|
}
|
||||||
|
private void ParseExpression(MethodAtom method, string type)
|
||||||
|
{
|
||||||
|
if (Tokens[pointer + 1].Equals(OP.Semicolon))
|
||||||
|
{
|
||||||
|
ParseSingleExpr(method, pointer, type);
|
||||||
|
pointer += 2;
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer + 1].Equals(OP.OpenParam))
|
||||||
|
{
|
||||||
|
ParseCall(method, type);
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer].Equals(OP.Sub))
|
||||||
|
{
|
||||||
|
ParseSingleExpr(method, pointer + 1, type);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add("INEG");
|
||||||
|
break;
|
||||||
|
case "double":
|
||||||
|
method.Code.Add("DNEG");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ParserException("Incompatible types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer + 1].Equals(OP.Add))
|
||||||
|
{
|
||||||
|
int prevpointer = pointer;
|
||||||
|
pointer += 2;
|
||||||
|
|
||||||
|
ParseExpression(method, type);
|
||||||
|
ParseSingleExpr(method, prevpointer, type);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add("IADD");
|
||||||
|
break;
|
||||||
|
case "double":
|
||||||
|
method.Code.Add("DADD");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ParserException("Incompatible types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer + 1].Equals(OP.Sub))
|
||||||
|
{
|
||||||
|
int prevpointer = pointer;
|
||||||
|
pointer += 2;
|
||||||
|
|
||||||
|
ParseExpression(method, type);
|
||||||
|
ParseSingleExpr(method, prevpointer, type);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add("ISUB");
|
||||||
|
break;
|
||||||
|
case "double":
|
||||||
|
method.Code.Add("DSUB");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ParserException("Incompatible types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer + 1].Equals(OP.Mul))
|
||||||
|
{
|
||||||
|
int prevpointer = pointer;
|
||||||
|
pointer += 2;
|
||||||
|
|
||||||
|
ParseExpression(method, type);
|
||||||
|
ParseSingleExpr(method, prevpointer, type);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add("IMUL");
|
||||||
|
break;
|
||||||
|
case "double":
|
||||||
|
method.Code.Add("DMUL");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ParserException("Incompatible types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer + 1].Equals(OP.Div))
|
||||||
|
{
|
||||||
|
int prevpointer = pointer;
|
||||||
|
pointer += 2;
|
||||||
|
|
||||||
|
ParseExpression(method, type);
|
||||||
|
ParseSingleExpr(method, prevpointer, type);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add("IDIV");
|
||||||
|
break;
|
||||||
|
case "double":
|
||||||
|
method.Code.Add("DDIV");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ParserException("Incompatible types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (Tokens[pointer + 1].Equals(OP.Mod))
|
||||||
|
{
|
||||||
|
int prevpointer = pointer;
|
||||||
|
pointer += 2;
|
||||||
|
|
||||||
|
ParseExpression(method, type);
|
||||||
|
ParseSingleExpr(method, prevpointer, type);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add("IMOD");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ParserException("Incompatible types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseCall(MethodAtom method, string type = null)
|
||||||
|
{
|
||||||
|
if (Methods.ContainsKey(Tokens[pointer].ToString()))
|
||||||
|
{
|
||||||
|
MethodAtom CallMethod = Methods[Tokens[pointer].ToString()];
|
||||||
|
if (type != null && type != CallMethod.Type)
|
||||||
|
throw new ParserException("Incompatible types when call method" + CallMethod.Name);
|
||||||
|
|
||||||
|
pointer += 2;
|
||||||
|
List<object> param = new List<object>();
|
||||||
|
while (!Tokens[pointer++].Equals(OP.CloseParam))
|
||||||
|
{
|
||||||
|
param.Add(Tokens[pointer]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param.Count != CallMethod.NumOfParams)
|
||||||
|
throw new ParserException("Wrong params when call method" + CallMethod.Name);
|
||||||
|
|
||||||
|
for (int i = 0; i < param.Count; i++)
|
||||||
|
{
|
||||||
|
ParseSingleExpr(method, pointer - 2 - i, CallMethod.Variables[i].Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
method.Code.Add(string.Format("CALL {0}", CallMethod.Name));
|
||||||
|
|
||||||
|
}
|
||||||
|
else throw new ParserException("Undefined method to call");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseSingleExpr(MethodAtom method, int pointer, string type)
|
||||||
|
{
|
||||||
|
if (Tokens[pointer] is StringBuilder)
|
||||||
|
{
|
||||||
|
if (type == "string")
|
||||||
|
method.Code.Add(string.Format("SLOAD {0}", Constants[Tokens[pointer++].ToString()]));
|
||||||
|
else
|
||||||
|
throw new ParserException("Incompatible type");
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer] is Number)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
if (!Tokens[pointer].ToString().Contains("."))
|
||||||
|
{
|
||||||
|
method.Code.Add(string.Format("ILOAD {0}", Tokens[pointer++].ToString()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else throw new ParserException("Incompatible type");
|
||||||
|
|
||||||
|
case "double":
|
||||||
|
method.Code.Add(string.Format("DLOAD {0}", Tokens[pointer++].ToString()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<Variable> NeededVars = method.Variables.FindAll(x => x.Name == Tokens[pointer].ToString());
|
||||||
|
if (NeededVars.Count != 0)
|
||||||
|
{
|
||||||
|
if (NeededVars[NeededVars.Count - 1].Type != type)
|
||||||
|
throw new ParserException("Incompatible type");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add(string.Format("LOADIVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
||||||
|
break;
|
||||||
|
case "double":
|
||||||
|
method.Code.Add(string.Format("LOADDVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
||||||
|
break;
|
||||||
|
case "string":
|
||||||
|
method.Code.Add(string.Format("LOADSVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else throw new ParserException("Can't parse sequence");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeclareVar(MethodAtom method)
|
||||||
|
{
|
||||||
|
method.Variables.Add(new Variable(idvar++, Tokens[pointer].ToString(), Tokens[pointer + 1].ToString()));
|
||||||
|
if (Tokens[pointer + 2].Equals(OP.Semicolon))
|
||||||
|
{
|
||||||
|
pointer += 3; return;
|
||||||
|
}
|
||||||
|
else if (Tokens[pointer + 2].Equals(OP.Assigment))
|
||||||
|
{
|
||||||
|
pointer += 3;
|
||||||
|
ParseExpression(method, method.Variables[idvar - 1].Type);
|
||||||
|
switch (method.Variables[idvar - 1].Type)
|
||||||
|
{
|
||||||
|
case "int":
|
||||||
|
method.Code.Add(string.Format("STOREIVAR {0}", idvar - 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "double":
|
||||||
|
method.Code.Add(string.Format("STOREDVAR {0}", idvar - 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "string":
|
||||||
|
method.Code.Add(string.Format("STORESVAR {0}", idvar - 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tokens[pointer].Equals(OP.Semicolon))
|
||||||
|
{
|
||||||
|
pointer++; return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new ParserException("Wrong variable defenition");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTypeOfVar(MethodAtom method, int pointer)
|
||||||
|
{
|
||||||
|
string result = null;
|
||||||
|
if (Tokens[pointer] is StringBuilder)
|
||||||
|
result = "string";
|
||||||
|
else if (Tokens[pointer] is Number)
|
||||||
|
{
|
||||||
|
if (Tokens[pointer].ToString().Contains("."))
|
||||||
|
result = "double";
|
||||||
|
else result = "int";
|
||||||
|
}
|
||||||
|
else if (Methods.ContainsKey(Tokens[pointer].ToString()))
|
||||||
|
{
|
||||||
|
result = Methods[Tokens[pointer].ToString()].Type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<Variable> isVariable = method.Variables.FindAll(x => x.Name == Tokens[pointer].ToString());
|
||||||
|
if (isVariable.Count == 0)
|
||||||
|
throw new ParserException("No defined variable with name "+Tokens[pointer].ToString());
|
||||||
|
else result = isVariable[isVariable.Count - 1].Type;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> code_types = new List<string>() { "int", "double", "string" };
|
||||||
|
}
|
||||||
|
}
|
53
CompilerVVM/ProcedureScanner.cs
Normal file
53
CompilerVVM/ProcedureScanner.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace CompilerVVM
|
||||||
|
{
|
||||||
|
class ProcedureScanner
|
||||||
|
{
|
||||||
|
public Dictionary<string, MethodAtom> Methods { get; set; }
|
||||||
|
int pointer;
|
||||||
|
|
||||||
|
public ProcedureScanner(IList<object> Tokens)
|
||||||
|
{
|
||||||
|
// TODO: Complete member initialization
|
||||||
|
pointer = 0;
|
||||||
|
ScanForMethods(Tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScanForMethods(IList<object> Tokens)
|
||||||
|
{
|
||||||
|
Methods = new Dictionary<string, MethodAtom>();
|
||||||
|
while (pointer != Tokens.Count)
|
||||||
|
{
|
||||||
|
MethodAtom method = null;
|
||||||
|
if (Tokens[pointer++].Equals("method"))
|
||||||
|
{
|
||||||
|
if (!Tokens[pointer].Equals("void") && !Tokens[pointer].Equals("int") &&
|
||||||
|
!Tokens[pointer].Equals("double") && !Tokens[pointer].Equals("string"))
|
||||||
|
{
|
||||||
|
throw new ProcedureException("Wrong method defenition");
|
||||||
|
}
|
||||||
|
int idvar = 0;
|
||||||
|
method = new MethodAtom(Tokens[++pointer].ToString());
|
||||||
|
method.Type = Tokens[pointer++ - 1].ToString();
|
||||||
|
if (!Tokens[pointer++].Equals(OP.OpenParam))
|
||||||
|
throw new ProcedureException("Wrong method defenition of method: "+method.Name);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (!Tokens[pointer].Equals(OP.CloseParam))
|
||||||
|
{
|
||||||
|
Variable a = new Variable(idvar++, Tokens[pointer].ToString(), Tokens[pointer + 1].ToString());
|
||||||
|
method.Variables.Add(a);
|
||||||
|
method.NumOfParams++;
|
||||||
|
pointer += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Methods.Add(method.Name, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
CompilerVVM/Program.cs
Normal file
43
CompilerVVM/Program.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CompilerVVM
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length != 1)
|
||||||
|
{
|
||||||
|
Console.WriteLine("No input file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TokenScanner scanner = null;
|
||||||
|
ProcedureScanner procscanner = null;
|
||||||
|
Parser parser = null;
|
||||||
|
CodeGen code = null;
|
||||||
|
Dictionary<string, string> TextConst = new Dictionary<string, string>();
|
||||||
|
using (System.IO.TextReader input = System.IO.File.OpenText(args[0]))
|
||||||
|
{
|
||||||
|
scanner = new TokenScanner(input, TextConst);
|
||||||
|
procscanner = new ProcedureScanner(scanner.Tokens);
|
||||||
|
parser = new Parser(scanner.Tokens, TextConst, procscanner.Methods);
|
||||||
|
|
||||||
|
code = new CodeGen(TextConst, procscanner.Methods);
|
||||||
|
ByteCode.GenerateByteCode(code.asm, args[0] + ".vvm");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine(e.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
293
CompilerVVM/TokenScanner.cs
Normal file
293
CompilerVVM/TokenScanner.cs
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace CompilerVVM
|
||||||
|
{
|
||||||
|
class TokenScanner
|
||||||
|
{
|
||||||
|
int idconst = 1;
|
||||||
|
private IList<object> tokens;
|
||||||
|
private IList<object> list;
|
||||||
|
public IList<object> Tokens { get { return tokens; } }
|
||||||
|
private void Scan(System.IO.TextReader input, Dictionary<string, string> dict)
|
||||||
|
{
|
||||||
|
while (input.Peek() != -1)
|
||||||
|
{
|
||||||
|
char ch = (char)input.Peek();
|
||||||
|
|
||||||
|
if (char.IsWhiteSpace(ch))
|
||||||
|
{
|
||||||
|
input.Read();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (char.IsLetter(ch) || ch == '_')
|
||||||
|
{
|
||||||
|
StringBuilder accum = new StringBuilder();
|
||||||
|
|
||||||
|
while (char.IsLetter(ch) || ch == '_' || char.IsNumber(ch))
|
||||||
|
{
|
||||||
|
accum.Append(ch);
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch = (char)input.Peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tokens.Add(accum.ToString());
|
||||||
|
}
|
||||||
|
else if (ch == '"')
|
||||||
|
{
|
||||||
|
StringBuilder accum = new StringBuilder();
|
||||||
|
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
throw new ScannerException("Unterminated string");
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ch = (char)input.Peek()) != '"')
|
||||||
|
{
|
||||||
|
accum.Append(ch);
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
throw new ScannerException("Unterminated string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.Read();
|
||||||
|
dict.Add(accum.ToString(), string.Format("text_const_{0}", idconst++));
|
||||||
|
this.tokens.Add(accum);
|
||||||
|
}
|
||||||
|
else if (char.IsDigit(ch))
|
||||||
|
{
|
||||||
|
StringBuilder accum = new StringBuilder();
|
||||||
|
|
||||||
|
while (char.IsDigit(ch) || ch == '.')
|
||||||
|
{
|
||||||
|
accum.Append(ch);
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch = (char)input.Peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tokens.Add(new Number(accum.ToString()));
|
||||||
|
}
|
||||||
|
else if (ch == '(')
|
||||||
|
{
|
||||||
|
this.tokens.Add(OP.OpenParam);
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
throw new ScannerException("Unterminated parameter section");
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ch = (char)input.Peek()) != ')')
|
||||||
|
{
|
||||||
|
if (char.IsLetter(ch) || ch == '_')
|
||||||
|
{
|
||||||
|
StringBuilder accum = new StringBuilder();
|
||||||
|
|
||||||
|
while (char.IsLetter(ch) || ch == '_')
|
||||||
|
{
|
||||||
|
accum.Append(ch);
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch = (char)input.Peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tokens.Add(accum.ToString());
|
||||||
|
}
|
||||||
|
else if (char.IsDigit(ch))
|
||||||
|
{
|
||||||
|
StringBuilder accum = new StringBuilder();
|
||||||
|
|
||||||
|
while (char.IsDigit(ch) || ch == '.')
|
||||||
|
{
|
||||||
|
accum.Append(ch);
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch = (char)input.Peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tokens.Add(new Number(accum.ToString()));
|
||||||
|
}
|
||||||
|
else if (ch == '"')
|
||||||
|
{
|
||||||
|
StringBuilder accum = new StringBuilder();
|
||||||
|
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
throw new ScannerException("Unterminated string");
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ch = (char)input.Peek()) != '"')
|
||||||
|
{
|
||||||
|
accum.Append(ch);
|
||||||
|
input.Read();
|
||||||
|
|
||||||
|
if (input.Peek() == -1)
|
||||||
|
{
|
||||||
|
throw new ScannerException("Unterminated string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.Read();
|
||||||
|
dict.Add(accum.ToString(), string.Format("text_const_{0}", idconst++));
|
||||||
|
this.tokens.Add(accum);
|
||||||
|
}
|
||||||
|
else if (char.IsWhiteSpace(ch) || ch == ',')
|
||||||
|
input.Read();
|
||||||
|
else switch (ch)
|
||||||
|
{
|
||||||
|
case '=':
|
||||||
|
input.Read();
|
||||||
|
if ((char)input.Peek() == '=')
|
||||||
|
{
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.Equal);
|
||||||
|
}
|
||||||
|
else this.tokens.Add(OP.Assigment);
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
input.Read();
|
||||||
|
if ((char)input.Peek() == '=')
|
||||||
|
{
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.LessEqual);
|
||||||
|
}
|
||||||
|
else this.tokens.Add(OP.Less);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
input.Read();
|
||||||
|
if ((char)input.Peek() == '=')
|
||||||
|
{
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.GreaterEqual);
|
||||||
|
}
|
||||||
|
else this.tokens.Add(OP.Greater);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
input.Read();
|
||||||
|
if ((char)input.Peek() == '=')
|
||||||
|
{
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.NotEqual);
|
||||||
|
}
|
||||||
|
else throw new Exception("!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tokens.Add(OP.CloseParam);
|
||||||
|
input.Read();
|
||||||
|
}
|
||||||
|
else switch (ch)
|
||||||
|
{
|
||||||
|
case ';':
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.Semicolon);
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.OpenBlock);
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.CloseBlock);
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.Add);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.Sub);
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.Mul);
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.Div);
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.Mod);
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
input.Read();
|
||||||
|
if ((char)input.Peek() == '=')
|
||||||
|
{
|
||||||
|
input.Read();
|
||||||
|
this.tokens.Add(OP.Equal);
|
||||||
|
}
|
||||||
|
else this.tokens.Add(OP.Assigment);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ScannerException("Scanner encountered unrecognized character '" + ch + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenScanner(TextReader input, Dictionary<string, string> TextConstant)
|
||||||
|
{
|
||||||
|
tokens = new List<object>();
|
||||||
|
this.Scan(input, TextConstant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum OP
|
||||||
|
{
|
||||||
|
Semicolon,
|
||||||
|
OpenBlock,
|
||||||
|
CloseBlock,
|
||||||
|
OpenParam,
|
||||||
|
CloseParam,
|
||||||
|
Assigment,
|
||||||
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
Less,
|
||||||
|
Greater,
|
||||||
|
LessEqual,
|
||||||
|
GreaterEqual,
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod
|
||||||
|
}
|
||||||
|
}
|
43
CompilerVVM/grammar.txt
Normal file
43
CompilerVVM/grammar.txt
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<program> := <method>+
|
||||||
|
|
||||||
|
<method> := method <type_method> <ident>(<param>* ) <block>
|
||||||
|
|
||||||
|
<type> := int | double | string
|
||||||
|
<type_method> := <type> | void
|
||||||
|
|
||||||
|
<ident> := <char> <ident_rest>*
|
||||||
|
<ident_rest> := <char> | <digit>
|
||||||
|
<digit> := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
||||||
|
|
||||||
|
<int> := <digit>+
|
||||||
|
<double> := <int>.<int>
|
||||||
|
<string> := " <char>? "
|
||||||
|
|
||||||
|
<param> := <type> <ident>
|
||||||
|
|
||||||
|
<block> := <call>;
|
||||||
|
| <ident> = <expr>;
|
||||||
|
| <type> <ident>;
|
||||||
|
| <type> <ident> = <expr>;
|
||||||
|
| if <condit> <block>
|
||||||
|
| if <condit> <block> else <block>
|
||||||
|
| while <condit> <block>
|
||||||
|
| do <block> until <condit>;
|
||||||
|
|
||||||
|
<condit> := <int> <cond_op> <int>
|
||||||
|
<cond_op> := < | > | == | <= | >=
|
||||||
|
|
||||||
|
<expr> := <int>
|
||||||
|
| <double>
|
||||||
|
| <string>
|
||||||
|
| <int> <arith_op> <int>
|
||||||
|
| <double> <arith_op> <double>
|
||||||
|
| <ident>
|
||||||
|
| <call>
|
||||||
|
|
||||||
|
<arith_op> := + | - | * | /
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue