Mercurial > projects > ddbg_continued
view 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 source
/* 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; }