Mercurial > projects > ddbg_continued
diff src/expression/expression.apd @ 1:4a9dcbd9e54f
-files of 0.13 beta
-fixes so that it now compiles with the current dmd version
author | marton@basel.hu |
---|---|
date | Tue, 05 Apr 2011 20:44:01 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/expression/expression.apd Tue Apr 05 20:44:01 2011 +0200 @@ -0,0 +1,1075 @@ +/* Ddbg - Win32 Debugger for the D programming language + * Copyright (c) 2007 Jascha Wetzel + * All rights reserved. See LICENSE.TXT for details. + */ + +APDProperties +{ + parser_type = lr +} + +APDDeclaration +{ +module expression.expression_apd; + +import codeview.decl; +import codeview.codeview; +import expression.evaluationcontext; +import expression.datahandler; +import util; + +//import internal.aaA; + + struct aaA + { + aaA *left; + aaA *right; + hash_t hash; + /* key */ + /* value */ + } + + struct BB + { + aaA*[] b; + size_t nodes; // total number of aaA nodes + } + +import std.demangle; +import std.stdio; + +import win32.winnt; + +/********************************************************************************************** + +**********************************************************************************************/ +bool castArrayIndex(ubyte[] data, string type, out size_t index) +{ + assert(type.length>0); + switch ( type[0] ) + { + case 'a': + if ( *cast(char*)data.ptr < 0 ) + throw new EvaluationException("Cannot access array with negative index"); + case 'h': + index = *cast(ubyte*)data.ptr; + return true; + case 's': + if ( *cast(short*)data.ptr < 0 ) + throw new EvaluationException("Cannot access array with negative index"); + case 't': + index = *cast(ushort*)data.ptr; + return true; + case 'i': + if ( *cast(int*)data.ptr < 0 ) + throw new EvaluationException("Cannot access array with negative index"); + case 'k': + index = *cast(uint*)data.ptr; + return true; + case 'l': + if ( *cast(long*)data.ptr < 0 ) + throw new EvaluationException("Cannot access array with negative index"); + case 'm': + index = cast(size_t)*cast(ulong*)data.ptr; + return true; + default: + } + return false; +} + +/********************************************************************************************** + +**********************************************************************************************/ +// debug = parser; +unittest +{ + bool test(string expr) + { + SyntaxTree* root; + bool success; + try success = parse(expr, root); + catch ( ParserException e ) { + debug(parser) writefln("%s", e.toString); + return false; + } + return success; + } + + assert(test("a.bc")); + assert(test("bc[def..ghij]")); + assert(!test("\"a\\\"\\\u2f85qwe '\"")); + assert(test("a.bc[def..ghij].klmno.pqrstu[0..'a'][\"a\\\"\\u2f85qwe '\"]")); + assert(!test("a.bc.[def..ghij]")); + assert(!test("[def..ghij]")); + assert(!test("a.")); + assert(test("asdf[0][i].qwer")); + assert(test("cast(uint)asdf")); + assert(test("(cast(mystruct)asdf).qwer")); + assert(test("(cast(string[])asdf)[0][2..13]")); + assert(test("(cast(char[string])asdf)[\"qwer\"]")); + assert(!test("(cast(mystruct)asdf).(cast(char[][])qwer)[0]")); + assert(test("cast(float)asdf.qwer")); + assert(!test("cast.qwer")); + assert(!test("cast(uint).qwer")); + assert(!test("cast(asdf.qwer).qwer")); + assert(test("(cast(string)mystruct.tzui)[0..4]")); + assert(test("cast(Vec!(float,3))mystruct")); + assert(test("cast(Vec!(float,3,\"asdf\",Vec!(float)))mystruct")); + assert(test("vertices[inds[10193]].y")); + assert(test("*cast(uint*)#eax")); +} + +} + +Whitespace +{ + regexp("[\\t\\n\\r ]+"); +} + + +/************************************************************************************************** + Expressions +**************************************************************************************************/ +Expr(EvaluationContext ctx, out SymbolData symdata) +{ + Deref Cast DotChain + { + DotChain(ctx, symdata); + Cast(ctx, symdata); + Deref(ctx, symdata); + } +} + +Deref(EvaluationContext ctx, ref SymbolData symdata) +{ + "*" Deref + { + if ( symdata is null ) + throw new EvaluationException("Invalid data for dereferencing"); + if ( symdata.type[0] != 'P' ) + throw new EvaluationException("Cannot dereference non-pointer of type "~demangleType(symdata.type)); + symdata.type = symdata.type[1..$]; + assert(symdata.type.length>0); + ubyte[] data = symdata.getData(ctx); + if ( data.length != size_t.sizeof ) { + throw new EvaluationException("Invalid pointer data size = "~.toString(data.length)); + } + symdata.ptr = (cast(size_t[])data)[0]; + symdata.len = ctx.codeView.sizeofMangled(symdata.type); + symdata.defered_load = true; + + Deref(ctx, symdata); + } + + epsilon; +} + +DotChain(EvaluationContext ctx, out SymbolData symdata) +{ + Register + { + Register(ctx, symdata); + } + + "(" !("(%d) Expression expected after (") + Expr !("(%d) ) expected") + ")" + RefExpr + { + Expr(ctx, symdata); + RefExpr(ctx, null, null, "", symdata); + } + + Ident + RefExpr + { + string id; + Ident(id); + + NamedSymbol[] symbols; + NamedSymbol symbol = ctx.findSymbol(id, symbols); + if ( symbol !is null ) + symdata = ctx.loadSymbolData(symbol); + else + debug DbgIO.println("symbol %s not found", id); + RefExpr(ctx, symbol, symbols, id, symdata); + } + + Lit + { Lit(symdata); } +} + +RefExpr(EvaluationContext ctx, NamedSymbol symbol, NamedSymbol[] symbols, string prefix, ref SymbolData symdata) +{ + //------------------------------------------------------------------------- + // . Operator + //------------------------------------------------------------------------- + "." Ident RefExpr + { + string id; + Ident(id); + prefix ~= "."~id; + + if ( symdata is null ) + { + symbol = ctx.findSymbol(prefix, symbols); + if ( symbol !is null ) + symdata = ctx.loadSymbolData(symbol); + } + else + { + switch ( symdata.type[0] ) + { + //--------------------------------------------------------------------------------- + // primitive types + case 'v': case 'b': case 'x': case 'g': case 'h': case 's': case 't': case 'i': case 'k': case 'l': case 'm': case 'f': + case 'd': case 'e': case 'o': case 'p': case 'j': case 'q': case 'r': case 'c': case 'a': case 'u': case 'w': + throw new EvaluationException( + "Type mismatch - unexpected . operator in expression of type "~demangleType(symdata.type) + ); + //--------------------------------------------------------------------------------- + // array properties + case 'G': + switch ( id ) + { + case "length": + symdata.type = symdata.type[1..$]; + size_t len = parseNumber(symdata.type); + symdata.type = "k"; + symdata.data = (cast(ubyte*)&len)[0..size_t.sizeof].dup; + symdata.defered_load = false; + break; + case "ptr": + // TODO: can this always be guaranteed? + assert(symdata.defered_load); + size_t ptr = symdata.ptr; + symdata.data = (cast(ubyte*)&ptr)[0..size_t.sizeof]; + symdata.defered_load = false; + symdata.type = symdata.type[1..$]; + parseNumber(symdata.type); + symdata.type = "P"~symdata.type; + break; + default: + throw new EvaluationException( + "Type mismatch - invalid property "~id~" after expression of type "~demangleType(symdata.type) + ); + } + break; + case 'A': + switch ( id ) + { + case "length": + ubyte[] data = symdata.getData(ctx); + symdata.type = "k"; + size_t len = (cast(size_t[])data)[0]; + symdata.data = (cast(ubyte*)&len)[0..size_t.sizeof].dup; + symdata.defered_load = false; + break; + case "ptr": + ubyte[] data = symdata.getData(ctx); + symdata.type = "k"; + size_t len = (cast(size_t[])data)[1]; + symdata.data = (cast(ubyte*)&len)[0..size_t.sizeof].dup; + symdata.defered_load = false; + break; + default: + throw new EvaluationException( + "Type mismatch - invalid property "~id~" after expression of type "~demangleType(symdata.type) + ); + } + break; + case 'H': + switch ( id ) + { + case "length": + ubyte[] data = symdata.getData(ctx); + symdata.ptr = *cast(size_t*)data.ptr; + symdata.len = BB.sizeof; + symdata.defered_load = true; + data = symdata.getData(ctx); + BB* bb = cast(BB*)data.ptr; + + symdata.type = "k"; + symdata.data = (cast(ubyte*)&bb.nodes)[0..size_t.sizeof].dup; + symdata.defered_load = false; + break; + default: + throw new EvaluationException( + "Type mismatch - invalid property "~id~" after expression of type "~demangleType(symdata.type) + ); + } + break; + //--------------------------------------------------------------------------------- + // references to structs/classes + case 'P': + symdata.type = symdata.type[1..$]; + if ( symdata.type[0] != 'C' && symdata.type[0] != 'S' ) + { + throw new EvaluationException( + "Type mismatch - unexpected . operator after expression of type "~demangleType("P"~symdata.type) + ); + } + + ubyte[] data = symdata.getData(ctx); + if ( symdata.data.length <= 0 ) + throw new EvaluationException("Subexpression evaluated to empty data"); + symdata.ptr = (cast(uint[])data)[0]; + symdata.len = ctx.codeView.sizeofMangled(symdata.type); + symdata.defered_load = true; + + if ( symdata.ptr == 0 ) + throw new EvaluationException("pointer is null"); + // fall through to struct handling + + //--------------------------------------------------------------------------------- + // classes/structs + case 'C': + case 'S': + symdata.type = symdata.type[1..$]; + string scu_name = demangleNameSkip(symdata.type); + assert ( symdata.type.length <= 0 ); + if ( (scu_name in ctx.codeView.UDTsByName) is null ) + throw new EvaluationException("unknown type \""~scu_name~"\""); + + LeafClassStruc lcs = cast(LeafClassStruc)ctx.codeView.UDTsByName[scu_name]; + LeafUnion lu; + LeafFieldList lfl; + uint type_length; + + if ( lcs !is null && lcs.field-0x1000 < ctx.codeView.type_strings.length ) { + Leaf[] fields = ctx.codeView.type_strings[lcs.field-0x1000]; + lfl = cast(LeafFieldList)fields[0]; + type_length = lcs.length.getUint(); + } + else + { + lu = cast(LeafUnion)ctx.codeView.UDTsByName[scu_name]; + if ( lu !is null && lu.field-0x1000 < ctx.codeView.type_strings.length ) { + Leaf[] fields = ctx.codeView.type_strings[lu.field-0x1000]; + lfl = cast(LeafFieldList)fields[0]; + type_length = lu.length.getUint(); + } + } + if ( lfl is null ) + throw new EvaluationException("invalid struct/class debug symbols"); + + size_t size, + offset; + if ( !ctx.findMember(id, lfl, size, offset, symdata.type) ) + throw new EvaluationException("struct \""~scu_name~"\" has no element \""~id~"\""); + assert ( symdata.type.length > 0 ); + debug(eval) DbgIO.println("member: type=%s size=%d offset=%d", symdata.type, size, offset); + + if ( !symdata.loadByteSlice(offset, offset+size) ) + throw new EvaluationException("invalid offset into struct for member \""~id~"\""); + break; + //--------------------------------------------------------------------------------- + // unsupported + default: + throw new EvaluationException("yet unsupported type "~demangleType(symdata.type)~" in expression"); + } + } + + RefExpr(ctx, symbol, symbols, prefix, symdata); + } + + //------------------------------------------------------------------------- + // [] Operator + //------------------------------------------------------------------------- + "[" !("(%d) Arguments expected after [") + Args !("(%d) ] expected") + "]" + RefExpr + { + if ( symdata is null ) + throw new EvaluationException("Unknown symbol "~prefix); + + SymbolData argdata; + size_t start, end; + Args(ctx, argdata, start, end); + + bool isIndex = argdata is null; + if ( !isIndex && castArrayIndex(argdata.getData(ctx), argdata.type, start) ) { + isIndex = true; + end = start+1; + } + + switch ( symdata.type[0] ) + { + //--------------------------------------------------------------------------------- + // primitive types + case 'v': case 'b': case 'x': case 'g': case 'h': case 's': case 't': case 'i': case 'k': case 'l': case 'm': case 'f': + case 'd': case 'e': case 'o': case 'p': case 'j': case 'q': case 'r': case 'c': case 'a': case 'u': case 'w': + // pointers, classes/structs + case 'P': case 'C': case 'S': + throw new EvaluationException( + "Type mismatch - unexpected [] operator after expression of type "~demangleType(symdata.type) + ); + //--------------------------------------------------------------------------------- + // static arrays + case 'G': + if ( !isIndex ) + throw new EvaluationException("Cannot access static array with index type "~demangleType(argdata.type)); + + symdata.type = symdata.type[1..$]; + size_t count = parseNumber(symdata.type); + assert(symdata.type.length>0); + + if ( end-start > 1 ) + { + if ( end > count ) + throw new EvaluationException("Array index out of bounds: "~.toString(start)~".."~.toString(end)~" ($="~.toString(count)~")"); + size_t size = ctx.codeView.sizeofMangled(symdata.type); + if ( symdata.defered_load ) { + symdata.ptr += start * size; + symdata.len = (end-start) * size; + } + else + symdata.data = symdata.data[start*size .. end*size]; + symdata.type = "G"~.toString(end-start)~symdata.type; + } + else + { + if ( !symdata.loadElementSlice(start, end, ctx.codeView) ) + throw new EvaluationException("Array index out of bounds: "~.toString(start)~".."~.toString(end)~" ($="~.toString(count)~")"); + } + break; + //--------------------------------------------------------------------------------- + // dynamic arrays + case 'A': + if ( !isIndex ) + throw new EvaluationException("Cannot access dynamic array with index type "~demangleType(argdata.type)); + + ubyte[] data = symdata.getData(ctx); + if ( data.length < 8 ) + throw new EvaluationException("Subexpression evaluated to empty data"); + + if ( end-start > 1 ) + { + if ( end > (cast(size_t[])data)[0] ) + throw new EvaluationException("Array index out of bounds: "~.toString(start)~".."~.toString(end)~" ($="~.toString(symdata.len)~")"); + size_t size = ctx.codeView.sizeofMangled(symdata.type[1..$]); + (cast(size_t[])data)[1] += start * size, + (cast(size_t[])data)[0] = end-start; + } + else + { + symdata.type = symdata.type[1..$]; + assert(symdata.type.length>0); + symdata.ptr = (cast(size_t[])data)[1]; + symdata.len = (cast(size_t[])data)[0] * ctx.codeView.sizeofMangled(symdata.type); + symdata.defered_load = true; + + if ( !symdata.loadElementSlice(start, end, ctx.codeView) ) + throw new EvaluationException("Array index out of bounds: "~.toString(start)~".."~.toString(end)~" ($="~.toString(symdata.len)~")"); + } + break; + //--------------------------------------------------------------------------------- + // associative arrays + case 'H': + int i; + for ( i = 1; i < symdata.type.length && std.string.find(lowercase, symdata.type[i]) < 0; ++i ) {} + string key_type = symdata.type[1..i+1], + val_type = symdata.type[i+1..$]; + size_t val_tsize = ctx.codeView.sizeofMangled(val_type); + TypeInfo key_ti = TypeInfoFromMangled(key_type); + + aaA* loadaaA(void* ptr) + { + if ( ptr is null ) + return null; + ubyte[] data; + data.length = aaA.sizeof+key_ti.tsize+val_tsize; + if ( data.length != ctx.process.readProcessMemory(cast(uint)ptr, data.ptr, data.length) ) + return null; + aaA* a = cast(aaA*)data.ptr; + if ( std.string.find(lowercase, key_type[0]) < 0 ) + switch ( key_type[0] ) + { + case 'A': + ubyte[] tmp = *cast(ubyte[]*)(a+1); + if ( tmp.length > ctx.process.MEMCHECK_MIN && ctx.process.isInvalidMem(cast(size_t)tmp.ptr, tmp.length) ) + return null; + data = new ubyte[tmp.length]; + if ( data.length != ctx.process.readProcessMemory(cast(size_t)tmp.ptr, data.ptr, data.length) ) + return null; + *cast(ubyte[]*)(a+1) = data; + break; + case 'P': + break; + default: + throw new EvaluationException("only basic, pointer and array key types are supported, yet"); + } + return a; + } + + ubyte[] findKey(size_t ptr, hash_t hash, ubyte[] key_data) + { + ubyte[] data; + data.length = BB.sizeof; + if ( data.length != ctx.process.readProcessMemory(ptr, data.ptr, data.length) ) + return null; + BB* bb = cast(BB*)data.ptr; + size_t blen = bb.b.length*size_t.sizeof; + debug(eval) DbgIO.println("%d nodes, bb.b.length=%d", bb.nodes, bb.b.length); + + if ( blen > ctx.process.MEMCHECK_MIN && ctx.process.isInvalidMem(cast(size_t)bb.b.ptr, blen) ) + return null; + data = new ubyte[blen]; + if ( data.length != ctx.process.readProcessMemory(cast(uint)bb.b.ptr, data.ptr, data.length) ) + return null; + bb.b = cast(aaA*[])data; + + uint i = hash % bb.b.length; + debug(eval) DbgIO.println("start index=%d", i); + aaA* a = loadaaA(bb.b[i]); + while ( a !is null ) + { + if ( hash == a.hash ) + { + debug(eval) DbgIO.println("equal 0x%x", a.hash); + auto cmp = key_ti.compare(key_data.ptr, a+1); + debug(eval) DbgIO.println("%s: %d == %d -> %d", key_ti, *cast(uint*)key_data.ptr, *cast(uint*)(a+1), cmp); + if ( cmp == 0 ) + return ((cast(ubyte*)(a+1))+key_ti.tsize)[0 .. val_tsize]; + a = cmp < 0 ? loadaaA(a.left) : loadaaA(a.right); + } + else { + debug(eval) DbgIO.println("not equal 0x%x", a.hash); + a = hash < a.hash ? loadaaA(a.left) : loadaaA(a.right); + } + } + return null; + } + + if ( key_type != argdata.type ) + throw new EvaluationException("Invalid key type for associative array. Expected "~demangleType(key_type)~" found "~demangleType(argdata.type)); + TypeInfo ti = TypeInfoFromMangled(argdata.type); + hash_t index_hash = ti.getHash(argdata.data.ptr); + + debug(eval) DbgIO.println("searching, hash=0x%x", index_hash); + ubyte[] data = symdata.getData(ctx); + symdata.data = findKey((cast(size_t[])data)[0], index_hash, argdata.getData(ctx)); + symdata.type = val_type; + break; + //--------------------------------------------------------------------------------- + // unsupported + default: + throw new EvaluationException("yet unsupported type "~demangleType(symdata.type)~" in expression"); + } + + RefExpr(ctx, symbol, null, null, symdata); + } + + //------------------------------------------------------------------------- + // end of refexpr + //------------------------------------------------------------------------- + epsilon + { + if ( symdata is null ) + throw new EvaluationException("Unknown symbol "~prefix); + } +} + +Args(EvaluationContext ctx, out SymbolData argdata, out size_t start, out size_t end) +{ + Expr + ".." !("(%d) Second slice argument expected") + Expr=Expr2 + { + SymbolData arg1, arg2; + Expr(ctx, arg1); + Expr2(ctx, arg2); + + bool isIndex = castArrayIndex(arg1.getData(ctx), arg1.type, start); + isIndex = isIndex && castArrayIndex(arg2.getData(ctx), arg2.type, end); + if ( !isIndex ) + throw new EvaluationException("Slices may only have integer indeces, not "~demangleType(arg1.type)~".."~demangleType(arg2.type)); + } + + Expr + { Expr(ctx, argdata); } +} + + +/************************************************************************************************** + Registers +**************************************************************************************************/ +Register(EvaluationContext ctx, out SymbolData symdata) +{ + RegName + { + string name; + ubyte width; + RegName(name, width); + + CONTEXT threadCtx; + uint context_flags; + context_flags |= CONTEXT_FULL; + context_flags |= CONTEXT_FLOATING_POINT; + context_flags |= CONTEXT_EXTENDED_REGISTERS; + if ( !ctx.getContext(threadCtx, context_flags) ) + throw new EvaluationException("Couldn't get main thread's context"); + + ubyte* ptr; + switch ( name[1..$] ) + { + case "ax": + case "eax": + case "al": ptr = cast(ubyte*)&threadCtx.Eax; break; + case "ah": ptr = (cast(ubyte*)&threadCtx.Eax)+1; break; + case "bx": + case "ebx": + case "bl": ptr = cast(ubyte*)&threadCtx.Ebx; break; + case "bh": ptr = (cast(ubyte*)&threadCtx.Ebx)+1; break; + case "cx": + case "ecx": + case "cl": ptr = cast(ubyte*)&threadCtx.Ecx; break; + case "ch": ptr = (cast(ubyte*)&threadCtx.Ecx)+1; break; + case "dx": + case "edx": + case "dl": ptr = cast(ubyte*)&threadCtx.Edx; break; + case "dh": ptr = (cast(ubyte*)&threadCtx.Edx)+1; break; + case "edi": + case "di": ptr = cast(ubyte*)&threadCtx.Edi; break; + case "esi": + case "si": ptr = cast(ubyte*)&threadCtx.Esi; break; + case "ebp": + case "bp": ptr = cast(ubyte*)&threadCtx.Ebp; break; + case "esp": + case "sp": ptr = cast(ubyte*)&threadCtx.Esp; break; + case "eip": ptr = cast(ubyte*)&threadCtx.Eip; break; + case "efl": ptr = cast(ubyte*)&threadCtx.EFlags; break; + case "cs": ptr = cast(ubyte*)&threadCtx.SegCs; break; + case "ds": ptr = cast(ubyte*)&threadCtx.SegDs; break; + case "es": ptr = cast(ubyte*)&threadCtx.SegEs; break; + case "fs": ptr = cast(ubyte*)&threadCtx.SegFs; break; + case "gs": ptr = cast(ubyte*)&threadCtx.SegGs; break; + default: + int i = name[$-1]-'0'; + if ( name[0..2] == "st" ) + ptr = cast(ubyte*)&((cast(real[])threadCtx.FloatSave.RegisterArea)[i]); + else if ( name[0..2] == "mm" ) + ptr = cast(ubyte*)&((cast(long[])threadCtx.ExtendedRegisters)[4+i*2]); + else if ( name[0..3] == "xmm" ) + ptr = cast(ubyte*)&((cast(long[])threadCtx.ExtendedRegisters)[20+i*2]); + else + assert(0); + } + + symdata = new SymbolData; + switch ( width ) + { + case 8: + symdata.type = "h"; + symdata.data = ptr[0..1].dup; + break; + case 16: + symdata.type = "t"; + symdata.data = ptr[0..2].dup; + break; + case 32: + symdata.type = "k"; + symdata.data = ptr[0..4].dup; + break; + case 64: + symdata.type = "m"; + symdata.data = ptr[0..8].dup; + break; + case 80: + symdata.type = "e"; + symdata.data = ptr[0..10].dup; + break; + case 128: + symdata.type = "G4k"; + symdata.data = ptr[0..16].dup; + break; + default: + assert(0, "unhandled register width "~.toString(width)); + } + } +} + +RegName(out string name, out ubyte width) +{ + regexp("#(e[abcd]x|e[ds]i|e[bs]p|eip|efl)") + { name = _ST_match; width = 32; } + + regexp("#([abcd]x|[ds]i|[bs]p|(cdefgs)s)") + { name = _ST_match; width = 16; } + + regexp("#[abcd][hl]") + { name = _ST_match; width = 8; } + + regexp("#st[0-7]") + { name = _ST_match; width = 8*real.sizeof; } + + regexp("#mm[0-7]") + { name = _ST_match; width = 64; } + + regexp("#xmm[0-7]") + { name = _ST_match; width = 128; } +} + + +/************************************************************************************************** + Casts +**************************************************************************************************/ +Cast(EvaluationContext ctx, ref SymbolData symdata) +{ + "cast" !("(%d) ( expected") + "(" !("(%d) Type expected") + Type !("(%d) ) expected") + ")" + { + symdata.type = ""; + Type(ctx, symdata.type); + if ( symdata.type.length <= 0 ) + throw new EvaluationException("Unknown type in cast"); + } + + epsilon; +} + +Type(EvaluationContext ctx, ref string mangled) +{ + BaseType QuantList + { + string unmangled; + BaseType(ctx, unmangled); + + switch ( unmangled ) + { + case "void": mangled = "v"; break; + case "bool": mangled = "b"; break; + case "byte": mangled = "g"; break; + case "ubyte": mangled = "h"; break; + case "char": mangled = "a"; break; + case "wchar": mangled = "u"; break; + case "dchar": mangled = "w"; break; + case "short": mangled = "s"; break; + case "ushort": mangled = "t"; break; + case "int": mangled = "i"; break; + case "uint": mangled = "k"; break; + case "long": mangled = "l"; break; + case "ulong": mangled = "m"; break; + case "float": mangled = "f"; break; + case "double": mangled = "d"; break; + case "real": mangled = "e"; break; + default: + Leaf lf; + if ( (unmangled in ctx.codeView.UDTsByName) is null ) + { + foreach ( un, l; ctx.codeView.UDTsByName ) + { + if ( std.string.find(un, "."~unmangled) > 0 ) { + lf = l; + break; + } + } + } + else + lf = ctx.codeView.UDTsByName[unmangled]; + + if ( lf !is null ) + { + string fqn; + switch ( lf.leaf_index ) + { + case LF_CLASS_16t: + mangled = "C"; + fqn = (cast(LeafClassStruc)lf).name; + break; + case LF_STRUCTURE_16t: + mangled = "S"; + fqn = (cast(LeafClassStruc)lf).name; + break; + case LF_ENUM_16t: + mangled = "E"; + fqn = (cast(LeafEnum)lf).name; + break; + default: + assert(0); + } + string[] parts = std.string.split(fqn, "."); + foreach ( p; parts ) { + mangled ~= .toString(p.length); + mangled ~= p; + } + } + else + throw new EvaluationException("Unknown BaseType "~unmangled); + break; + } + + QuantList(ctx, mangled); + } +} + +BaseType(EvaluationContext ctx, out string type) +{ + FQNIdent TplParams + { + FQNIdent(type); + string str; + TplParams(ctx, str); + type ~= str; + } +} + +QuantList(EvaluationContext ctx, ref string mangled) +{ + Quantifier QuantList + { + Quantifier(ctx, mangled); + QuantList(ctx, mangled); + } + + epsilon; +} + +Quantifier(EvaluationContext ctx, ref string mangled) +{ + "*" + { mangled = "P"~mangled; } + + "[" "]" + { mangled = "A"~mangled; } + + "[" + Integer !("(%d) ] expected") + "]" + { + ulong len; + Integer(len); + mangled = "G"~.toString(len)~mangled; + } + + "[" !("(%d) ], type or size expected") + Type !("(%d) ] expected") + "]" + { + string index_mangled; + Type(ctx, index_mangled); + mangled = "H"~index_mangled~mangled; + } +} + +TplParams(EvaluationContext ctx, out string str) +{ + "!" !("(%d) ( expected") + "(" !("(%d) Template parameters expected") + TplParam + TplParams2 !("(%d) ) expected") + ")" + { + string tmp; + TplParam(ctx, tmp); + str = "!("~tmp; + TplParams2(ctx, tmp); + str ~= tmp~")"; + } + + epsilon; +} + +TplParams2(EvaluationContext ctx, out string str) +{ + "," !("(%d) Template parameter expected") + TplParam + TplParams2 + { + TplParam(ctx, str); + string tmp; + TplParams2(ctx, tmp); + str ~= tmp; + } + + epsilon; +} + +TplParam(EvaluationContext ctx, out string str) +{ + Type { Type(ctx, str); } + StrLit { StrLit(str); } +} + + +/************************************************************************************************** + Terminals +**************************************************************************************************/ +Lit(out SymbolData litdata) +{ + Sign Integer IntegerSuffix + { + litdata = new SymbolData; + IntegerSuffix(litdata.type); + ulong val; + Integer(val); + + if ( val > 0x7fffffffffffffff ) + litdata.type = "m"; + else if ( val > 0xffffffff ) + litdata.type = litdata.type[0]=='i'||litdata.type[0]=='l'?"l":"m"; + else if ( val > 0x7fffffff && litdata.type[0] == 'i' ) + litdata.type = "k"; + + litdata.data = (cast(ubyte*)&val)[0 .. (litdata.type[0] == 'k' || litdata.type[0] == 'i')?uint.sizeof:ulong.sizeof].dup; + Sign(litdata); + } + + // String + regexp("\"(([^\"\\\\]*(\\\\(['\"\\?\\\\abfnrtv]|(x[0-9a-fA-F]{2})|(u[0-9a-fA-F]{4})|(U[0-9a-fA-F]{8})))?)*)\"") + { + litdata = new SymbolData; + litdata.type = "Aa"; + litdata.data = cast(ubyte[])_ST_match; + } + + // Char + regexp("'(([^'\\\\]|(\\\\(['\"\\?\\\\abfnrtv]|(x[0-9a-fA-F]{2})|(u[0-9a-fA-F]{4})|(U[0-9a-fA-F]{8})))))'") + { + litdata = new SymbolData; + litdata.type = "a"; + litdata.data = cast(ubyte[])_ST_match[0..1]; + } +} + +StrLit(out string str) +{ + // Integer + Integer + { + ulong val; + Integer(val); + str = .toString(val); + } + + // String + regexp("\"(([^\"\\\\]*(\\\\(['\"\\?\\\\abfnrtv]|(x[0-9a-fA-F]{2})|(u[0-9a-fA-F]{4})|(U[0-9a-fA-F]{8})))?)*)\"") + { str = _ST_match; } + + // Char + regexp("'(([^'\\\\]|(\\\\(['\"\\?\\\\abfnrtv]|(x[0-9a-fA-F]{2})|(u[0-9a-fA-F]{4})|(U[0-9a-fA-F]{8})))))'") + { str = _ST_match; } +} + +Ident(out string id) +{ + regexp("[a-zA-Z_][_a-zA-Z0-9]*") + { id = _ST_match; } +} + +FQNIdent(out string id) +{ + Ident + { Ident(id); } + + FQNIdent "." Ident + { + FQNIdent(id); + string tmp; + Ident(tmp); + id ~= "."~tmp; + } +} + +/************************************************************************************************** + Integers +**************************************************************************************************/ +Integer(out ulong val) +{ + // hex + regexp("0[xX][0-9a-fA-F_]+") + { + foreach ( b; _ST_match[2..$] ) + { + val <<= 4; + if ( b > 'F' ) + val |= b-'W'; + else if ( b > '9' ) + val |= b-'7'; + else + val |= b-'0'; + } + } + + // binary + regexp("0[bB][01_]+") + { + foreach ( b; _ST_match[2..$] ) + { + val <<= 1; + if ( b == '1' ) + val |= 1; + } + } + + // octal + regexp("0[0-7_]+") + { + foreach ( b; _ST_match[1..$] ) { + val <<= 3; + val |= b-'0'; + } + } + + // decimal + regexp("0|([1-9][0-9_]*)") + { + foreach ( b; _ST_match ) { + val *= 10; + val += b-'0'; + } + } +} + +IntegerSuffix(out string type) +{ + "L" "u" + { type = "m"; } + + "L" "U" + { type = "m"; } + + "u" "L" + { type = "m"; } + + "U" "L" + { type = "m"; } + + "L" + { type = "l"; } + + regexp("[uU]") + { type = "k"; } + + epsilon + { type = "i"; } +} + +Sign(ref SymbolData symdata) +{ + "-" + { + switch ( symdata.type[0] ) + { + case 'i': + *cast(int*)symdata.data.ptr = 0-*cast(int*)symdata.data.ptr; + break; + case 'k': + *cast(uint*)symdata.data.ptr = 0-*cast(uint*)symdata.data.ptr; + break; + case 'l': + *cast(long*)symdata.data.ptr = 0-*cast(long*)symdata.data.ptr; + break; + case 'm': + *cast(ulong*)symdata.data.ptr = 0-*cast(ulong*)symdata.data.ptr; + break; + default: + assert(0); + } + } + + epsilon; +}