summaryrefslogtreecommitdiffstats
path: root/debian/uncrustify-trinity/uncrustify-trinity-0.73.0/tests/input/d/Lexer.d
diff options
context:
space:
mode:
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.73.0/tests/input/d/Lexer.d')
-rw-r--r--debian/uncrustify-trinity/uncrustify-trinity-0.73.0/tests/input/d/Lexer.d2335
1 files changed, 2335 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.73.0/tests/input/d/Lexer.d b/debian/uncrustify-trinity/uncrustify-trinity-0.73.0/tests/input/d/Lexer.d
new file mode 100644
index 00000000..004d9d8a
--- /dev/null
+++ b/debian/uncrustify-trinity/uncrustify-trinity-0.73.0/tests/input/d/Lexer.d
@@ -0,0 +1,2335 @@
+/+
+ Copyright (c) 1999-2006 by Digital Mars
+ All Rights Reserved
+ written by Walter Bright www.digitalmars.com
+ License for redistribution is by either the Artistic License in artistic.txt, or the GNU General Public License in gnu.txt.
+ See the included readme.txt for details.
+ D Language conversion by: J Duncan
++/
+
+/**
+ d language lexer
+*/
+
+module dparser.Lexer;
+
+import dparser.Root;
+
+import dparser.Tokens;
+import dparser.Token;
+import dparser.Keyword;
+
+import dparser.Types;
+
+import dparser.Module;
+import dparser.Identifier;
+import dparser.unialpha;
+
+import dparser.OutBuffer;
+
+//private import std.ctype;
+//private import std.string;
+//import dwf.core.debugapi;
+
+int errno = 0;
+
+//#if _WIN32 && __DMC__
+// from \dm\src\include\setlocal.h
+//extern "C" char * __cdecl __locale_decpoint;
+char* __locale_decpoint;
+//#endif
+//const uint LS = 0x2028; // UTF line separator
+//const uint PS = 0x2029; // UTF paragraph separator
+
+//extern int isUniAlpha(unsigned u);
+//extern int HtmlNamedEntity(unsigned char *p, int length);
+
+/**
+ Lexer object
+*/
+
+class Lexer
+{
+
+ static Identifier[char[]] stringtable;
+ static OutBuffer stringbuffer;
+ static Token* freelist;
+
+ Token token; // current token
+ Module mod; // current module
+ Loc loc; // for error messages
+ ubyte *base; // pointer to start of buffer
+ ubyte *end; // past end of buffer
+ ubyte *p; // current character
+ int doDocComment; // collect doc comment information
+ int anyToken; // !=0 means seen at least one token
+ int commentToken; // !=0 means comments are TOKcomment's
+
+
+ this( Module mod, ubyte* base, uint begoffset, uint endoffset, int doDocComment, int commentToken )
+ {
+ if( stringbuffer is null )
+ stringbuffer = new OutBuffer;
+ loc = Loc(mod, 1);
+
+ this.base = base;
+ this.end = base + endoffset;
+ this.p = base + begoffset;
+ this.mod = mod;
+ this.doDocComment = doDocComment;
+ this.commentToken = commentToken;
+
+ /*
+ If first line starts with '#!', ignore the line
+ */
+
+ if( p[0] == '#' && p[1] =='!' )
+ {
+ p += 2;
+ while( true )
+ {
+ ubyte c = *p;
+ switch( c )
+ {
+ case '\n':
+ p++;
+ break;
+
+ case '\r':
+ p++;
+ if( *p == '\n' )
+ p++;
+ break;
+
+ case 0:
+ case 0x1A:
+ break;
+
+ default:
+ if( c & 0x80 )
+ {
+ uint u = decodeUTF();
+ if( u == PS || u == LS )
+ break;
+ }
+ p++;
+ continue;
+ }
+ break;
+ }
+
+ loc.linnum = 2;
+ }
+
+ }
+
+
+
+ // generate a unique identifier for this string
+ static Identifier idPool( in char[] str )
+ {
+// StringValue sv;
+// uint len = s.length;
+// StringValue sv = stringtable.update(s, len);
+// Identifier* id = cast(Identifier*) sv.ptrvalue;
+// if( id is null )
+ if( (str in stringtable) == null )
+ {
+ stringtable[str] = new Identifier( str, TOK.TOKidentifier );
+ }
+ return stringtable[str];
+ }
+
+ static void initKeywords()
+ {
+ // build character map
+ cmtable_init();
+
+ // create keyword tokens & identifiers
+ dparser.Keyword.initKeywords();
+
+ // create standard lexer tokens
+ dparser.Token.createLexerTokens();
+ }
+
+ // Combine two document comments into one.
+ static char[] combineComments( char[] c1, char[] c2 )
+ {
+ char[] c = c2;
+ if( c1.length )
+ {
+ c = c1;
+ if( c2.length )
+ {
+ c = c1 ~ "\n" ~ c2;
+ }
+ }
+ return c;
+ }
+
+ // Decode UTF character. Issue error messages for invalid sequences. Return decoded character, advance p to last character in UTF sequence.
+ //! fix
+ uint decodeUTF()
+ {
+ ubyte* s = p;
+ ubyte c = *s;
+
+ assert( c & 0x80 );
+ if( !(c & 0x80) )
+ return c;
+
+ return cast(uint) 'X';
+ /*
+ dchar u;
+ uint len;
+
+
+
+ // Check length of remaining string up to 6 UTF-8 characters
+ for( len = 1; len < 6 && s[len]; len++ )
+ {
+
+ }
+ /+
+ uint idx = 0;
+ char* msg = utf_decodeChar( s, len, &idx, &u );
+ p += idx - 1;
+ if( msg )
+ {
+ error(msg);
+ }
+ +/
+ return u;
+ */
+ }
+
+ void error( ... )
+ {
+ if( (mod !is null) && !global.gag )
+ {
+ writefln( formatLoc( loc, _arguments, _argptr ) );
+ /*
+ char[] p = loc.toChars();
+ if( p.length )
+ writef( "%s: ", p );
+ writefx( stdout, _arguments, _argptr, 1 );
+ */
+ if( global.errors >= global.max_errors ) // moderate blizzard of cascading messages
+ throw new Exception( "too many errors" );
+ }
+
+ global.errors++;
+ }
+
+ void errorLoc(Loc loc, ...)
+ {
+ if( (mod !is null) && !global.gag )
+ {
+ writefln( formatLoc( loc, _arguments, _argptr ) );
+ /*
+ char[] p = loc.toChars();
+ if( p.length )
+ writef("%s: ", p);
+ writefx(stdout, _arguments, _argptr, 1);
+ */
+ if( global.errors >= 20 ) // moderate blizzard of cascading messages
+ throw new Exception( "too many errors" );
+ }
+
+ global.errors++;
+ }
+
+
+ TOK nextToken()
+ {
+ if( token.next )
+ {
+ Token* t = token.next;
+ memcpy( &token, t, Token.sizeof );
+// t.next = freelist;
+// freelist = t;
+ }
+ else
+ {
+ scan( &token );
+ }
+// token.print();
+ return token.value;
+ }
+
+ Token* peek( inout Token ct )
+ {
+ Token* t;
+ if( ct.next )
+ t = ct.next;
+ else
+ {
+ t = new Token;
+ scan( t );
+ t.next = null;
+ ct.next = t;
+ }
+ return t;
+ }
+
+ // Turn next token in buffer into a token.
+
+ void scan( Token* t )
+ {
+// debug writefln("scan token");
+ uint lastLine = loc.linnum;
+ uint linnum;
+ t.blockComment = null;
+ t.lineComment = null;
+ while( true )
+ {
+ t.ptr = p;
+// debug writefln( " p = %d, *p = ", cast(uint)p, cast(char)*p );
+ switch( *p )
+ {
+ case 0:
+ case 0x1a:
+ t.value = TOK.TOKeof; // end of file
+// debug writefln( " EOF" );
+ return;
+
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ p++;
+// debug writefln( " whitespace" );
+ continue; // skip white space
+
+ case '\r':
+// debug writefln( " cr" );
+ p++;
+ if( *p != '\n' ) // if CR stands by itself
+ loc.linnum++;
+ continue; // skip white space
+
+ case '\n':
+// debug writefln( " nl" );
+ p++;
+ loc.linnum++;
+ continue; // skip white space
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ t.value = number(t);
+ return;
+
+/*
+ #if CSTRINGS
+ case '\'':
+ t.value = charConstant(t, 0);
+ return;
+
+ case '"':
+ t.value = stringConstant(t,0);
+ return;
+
+ case 'l':
+ case 'L':
+ if( p[1] == '\'')
+ {
+ p++;
+ t.value = charConstant(t, 1);
+ return;
+ }
+ else if( p[1] == '"')
+ {
+ p++;
+ t.value = stringConstant(t, 1);
+ return;
+ }
+ #else
+*/
+ case '\'':
+// debug writefln( " char" );
+ t.value = charConstant(t,0);
+ return;
+
+ case 'r':
+// debug writefln( " wysiwyg" );
+ if( p[1] != '"')
+ goto case_identifier;
+ p++;
+ case '`':
+ t.value = wysiwygStringConstant(t, *p);
+ return;
+
+ case 'x':
+// debug writefln( " hex string" );
+ if( p[1] != '"')
+ goto case_identifier;
+ p++;
+ t.value = hexStringConstant(t);
+ return;
+
+
+ case '"':
+// debug writefln( " string" );
+ t.value = escapeStringConstant( t, 0 );
+// debug writefln( t.ustring );
+ return;
+
+ case '\\': // escaped string literal
+// debug writefln( " escaped string literal" );
+ uint c;
+ stringbuffer.offset = 0;
+ do
+ {
+ p++;
+ c = escapeSequence();
+ stringbuffer.write(c);
+ } while (*p == '\\');
+// t.len = stringbuffer.offset;
+// stringbuffer.write(cast(byte)0);
+ t.ustring = stringbuffer.toString;
+// memcpy( t.ustring.ptr, stringbuffer.data, stringbuffer.offset );
+ t.postfix = 0;
+ t.value = TOK.TOKstring;
+ return;
+
+ case 'l':
+ case 'L':
+// #endif
+
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'm': case 'n': case 'o':
+ case 'p': case 'q': /*case 'r':*/ case 's': case 't':
+ case 'u': case 'v': case 'w': /*case 'x':*/ case 'y':
+ case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z':
+ case '_':
+ case_identifier:
+ {
+// debug writefln( " identifier" );
+ ubyte c;
+ do
+ {
+ c = *++p;
+ } while( isidchar(c) || (c & 0x80 && isUniAlpha( decodeUTF())) );
+
+// sv = stringtable.update((char *)t.ptr, p - t.ptr);
+ char[] tmp;
+ tmp.length = p - t.ptr;
+ memcpy( tmp.ptr, t.ptr, p - t.ptr );
+ Identifier id;
+ Identifier* pid = tmp in stringtable;
+ if( pid )
+ {
+ id = *pid;
+ }
+
+ if( id is null )
+ {
+ id = new Identifier( tmp, TOK.TOKidentifier );
+ stringtable[tmp] = id;
+ }
+
+ t.identifier = id;
+ t.value = cast(TOK) id.value;
+ anyToken = 1;
+
+ // if special identifier token
+ if( *t.ptr == '_')
+ {
+ static char date[11+1];
+ static char time[8+1];
+ static char timestamp[24+1];
+
+ if( !date[0] ) // lazy evaluation
+ {
+ //!!
+ /+
+ time_t t;
+ char *p;
+ .time(&t);
+ p = ctime(&t);
+ assert(p);
+ sprintf(date.ptr, "%.6s %.4s", p + 4, p + 20);
+ sprintf(time.ptr, "%.8s", p + 11);
+ sprintf(timestamp.ptr, "%.24s", p);
+ +/
+ }
+
+ if( mod && id is Id.FILE )
+ {
+ t.value = TOK.TOKstring;
+ if( loc.filename.length )
+ t.ustring = loc.filename;
+ else
+ t.ustring = mod.identifier.toChars();
+ goto Llen;
+ }
+ else if( mod && id == Id.LINE )
+ {
+ t.value = TOK.TOKint64v;
+ t.uns64value = loc.linnum;
+ }
+ else if( id == Id.DATE )
+ {
+ t.value = TOK.TOKstring;
+ //! t.ustring = date;
+ goto Llen;
+ }
+ else if( id == Id.TIME )
+ {
+ t.value = TOK.TOKstring;
+ //! t.ustring = time;
+ goto Llen;
+ }
+ else if( id == Id.TIMESTAMP )
+ {
+ t.value = TOK.TOKstring;
+ //! t.ustring = timestamp;
+ Llen:
+ t.postfix = 0;
+// t.len = strlen((char *)t.ustring);
+ }
+ }
+ //printf("t.value = %d\n",t.value);
+ return;
+ }
+
+ // comments
+ case '/':
+ p++;
+ switch( *p )
+ {
+ case '=':
+ p++;
+ t.value = TOK.TOKdivass;
+ return;
+
+ case '*': // '/*'
+ p++;
+ linnum = loc.linnum;
+ while( true )
+ {
+ while( true )
+ {
+ ubyte c = *p;
+ switch( c )
+ {
+ case '/':
+ break;
+
+ case '\n':
+ loc.linnum++;
+ p++;
+ continue;
+
+ case '\r':
+ p++;
+ if( *p != '\n')
+ loc.linnum++;
+ continue;
+
+ case 0:
+ case 0x1A:
+ error("unterminated /* */ comment");
+ p = end;
+ t.value = TOK.TOKeof;
+ return;
+
+ default:
+ if( c & 0x80)
+ {
+ uint u = decodeUTF();
+ if( u == PS || u == LS )
+ loc.linnum++;
+ }
+ p++;
+ continue;
+ }
+ break;
+ }
+ p++;
+ if( p[-2] == '*' && p - 3 != t.ptr )
+ break;
+ }
+
+ if( commentToken )
+ {
+ t.value = TOK.TOKcomment;
+ return;
+ }
+ // if /** but not /**/
+ else if( doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr )
+ getDocComment( t, lastLine == linnum ); //! ?
+ continue;
+
+ case '/': // do // style comments
+ linnum = loc.linnum;
+ while (1)
+ {
+ ubyte c = *++p;
+ switch (c)
+ {
+ case '\n':
+ break;
+
+ case '\r':
+ if( p[1] == '\n')
+ p++;
+ break;
+
+ case 0:
+ case 0x1a:
+ if( commentToken )
+ {
+ p = end;
+ t.value = TOK.TOKcomment;
+ return;
+ }
+ if( doDocComment && t.ptr[2] == '/' )
+ getDocComment( t, lastLine == linnum );
+ p = end;
+ t.value = TOK.TOKeof;
+ return;
+
+ default:
+ if( c & 0x80)
+ {
+ uint u = decodeUTF();
+ if( u == PS || u == LS)
+ break;
+ }
+ continue;
+ }
+ break;
+ }
+
+ if( commentToken )
+ {
+ p++;
+ loc.linnum++;
+ t.value = TOK.TOKcomment;
+ return;
+ }
+ if( doDocComment && t.ptr[2] == '/' )
+ getDocComment( t, lastLine == linnum );
+
+ p++;
+ loc.linnum++;
+ continue;
+
+ case '+':
+ { int nest;
+ linnum = loc.linnum;
+ p++;
+ nest = 1;
+ while (1)
+ {
+ ubyte c = *p;
+ switch (c)
+ {
+ case '/':
+ p++;
+ if( *p == '+')
+ {
+ p++;
+ nest++;
+ }
+ continue;
+
+ case '+':
+ p++;
+ if( *p == '/')
+ {
+ p++;
+ if( --nest == 0)
+ break;
+ }
+ continue;
+
+ case '\r':
+ p++;
+ if( *p != '\n')
+ loc.linnum++;
+ continue;
+
+ case '\n':
+ loc.linnum++;
+ p++;
+ continue;
+
+ case 0:
+ case 0x1A:
+ error("unterminated /+ +/ comment");
+ p = end;
+ t.value = TOK.TOKeof;
+ return;
+
+ default:
+ if( c & 0x80 )
+ {
+ uint u = decodeUTF();
+ if( u == PS || u == LS)
+ loc.linnum++;
+ }
+ p++;
+ continue;
+ }
+ break;
+ }
+ if( commentToken )
+ {
+ t.value = TOK.TOKcomment;
+ return;
+ }
+ if( doDocComment && t.ptr[2] == '+' && p - 4 != t.ptr )
+ {
+ // if /++ but not /++/
+ getDocComment(t, lastLine == linnum);
+ }
+ continue;
+ }
+ default:
+ break;
+ }
+ t.value = TOK.TOKdiv;
+ return;
+
+ case '.':
+ p++;
+ if( isdigit(*p))
+ {
+ p--;
+ t.value = inreal(t);
+ }
+ else if( p[0] == '.')
+ {
+ if( p[1] == '.')
+ {
+ p += 2;
+ t.value = TOK.TOKdotdotdot;
+ }
+ else
+ {
+ p++;
+ t.value = TOK.TOKslice;
+ }
+ }
+ else
+ t.value = TOK.TOKdot;
+ return;
+
+ case '&':
+ p++;
+ if( *p == '=')
+ {
+ p++;
+ t.value = TOK.TOKandass;
+ }
+ else if( *p == '&')
+ {
+ p++;
+ t.value = TOK.TOKandand;
+ }
+ else
+ t.value = TOK.TOKand;
+ return;
+
+ // |, ||, |=
+ case '|':
+ p++;
+ if( *p == '=' )
+ { p++;
+ t.value = TOK.TOKorass;
+ }
+ else if( *p == '|')
+ { p++;
+ t.value = TOK.TOKoror;
+ }
+ else
+ t.value = TOK.TOKor;
+ return;
+
+ case '-':
+ p++;
+ if( *p == '=')
+ { p++;
+ t.value = TOK.TOKminass;
+ }
+ else if( *p == '-')
+ { p++;
+ t.value = TOK.TOKminusminus;
+ }
+ else
+ t.value = TOK.TOKmin;
+ return;
+
+ // +, +=, ++
+ case '+':
+ p++;
+ if( *p == '=')
+ {
+ p++;
+ t.value = TOK.TOKaddass; // +=
+ }
+ else if( *p == '+')
+ { p++;
+ t.value = TOK.TOKplusplus; // ++
+ }
+ else
+ t.value = TOK.TOKadd; // +
+ return;
+
+ // <, <=, <<=, <<, <>=, <>
+ case '<':
+ p++;
+ if( *p == '=')
+ { p++;
+ t.value = TOK.TOKle; // <=
+ }
+ else if( *p == '<')
+ { p++;
+ if( *p == '=')
+ { p++;
+ t.value = TOK.TOKshlass; // <<=
+ }
+ else
+ t.value = TOK.TOKshl; // <<
+ }
+ else if( *p == '>')
+ { p++;
+ if( *p == '=')
+ { p++;
+ t.value = TOK.TOKleg; // <>=
+ }
+ else
+ t.value = TOK.TOKlg; // <>
+ }
+ else
+ t.value = TOK.TOKlt; // <
+ return;
+
+ // >, >>, >>>, >=, >>=, >>>=
+ case '>':
+ p++;
+ if( *p == '=')
+ { p++;
+ t.value = TOK.TOKge; // >=
+ }
+ else if( *p == '>')
+ { p++;
+ if( *p == '=')
+ { p++;
+ t.value = TOK.TOKshrass; // >>=
+ }
+ else if( *p == '>')
+ { p++;
+ if( *p == '=')
+ { p++;
+ t.value = TOK.TOKushrass; // >>>=
+ }
+ else
+ t.value = TOK.TOKushr; // >>>
+ }
+ else
+ t.value = TOK.TOKshr; // >>
+ }
+ else
+ t.value = TOK.TOKgt; // >
+ return;
+
+ case '!':
+ p++;
+ if( *p == '=')
+ { p++;
+ if( *p == '=')
+ {
+ p++;
+ t.value = TOK.TOKnotidentity; // !==
+ }
+ else
+ t.value = TOK.TOKnotequal; // !=
+ }
+ else if( *p == '<')
+ {
+ p++;
+ if( *p == '>')
+ {
+ p++;
+ if( *p == '=')
+ {
+ p++;
+ t.value = TOK.TOKunord; // !<>=
+ }
+ else
+ t.value = TOK.TOKue; // !<>
+ }
+ else if( *p == '=')
+ {
+ p++;
+ t.value = TOK.TOKug; // !<=
+ }
+ else
+ t.value = TOK.TOKuge; // !<
+ }
+ else if( *p == '>')
+ { p++;
+ if( *p == '=')
+ {
+ p++;
+ t.value = TOK.TOKul; // !>=
+ }
+ else
+ t.value = TOK.TOKule; // !>
+ }
+ else
+ t.value = TOK.TOKnot; // !
+ return;
+
+ case '=':
+ p++;
+ if( *p == '=')
+ {
+ p++;
+ if( *p == '=')
+ {
+ p++;
+ t.value = TOK.TOKidentity; // ===
+ }
+ else
+ t.value = TOK.TOKequal; // ==
+ }
+ else
+ t.value = TOK.TOKassign; // =
+ return;
+
+ case '~':
+ p++;
+ if( *p == '=' )
+ {
+ p++;
+ t.value = TOK.TOKcatass; // ~=
+ }
+ else
+ t.value = TOK.TOKtilde; // ~
+ return;
+
+ // SINGLE
+ case '(': p++; t.value = TOK.TOKlparen; return;
+ case ')': p++; t.value = TOK.TOKrparen; return;
+ case '[': p++; t.value = TOK.TOKlbracket; return;
+ case ']': p++; t.value = TOK.TOKrbracket; return;
+ case '{': p++; t.value = TOK.TOKlcurly; return;
+ case '}': p++; t.value = TOK.TOKrcurly; return;
+ case '?': p++; t.value = TOK.TOKquestion; return;
+ case ',': p++; t.value = TOK.TOKcomma; return;
+ case ';': p++; t.value = TOK.TOKsemicolon; return;
+ case ':': p++; t.value = TOK.TOKcolon; return;
+ case '$': p++; t.value = TOK.TOKdollar; return;
+ // DOUBLE
+ case '*': p++; if( *p == '=' ) { p++; t.value = TOK.TOKmulass; } else t.value = TOK.TOKmul; return;
+ case '%': p++; if( *p == '=' ) { p++; t.value = TOK.TOKmodass; } else t.value = TOK.TOKmod; return;
+ case '^': p++; if( *p == '=' ) { p++; t.value = TOK.TOKxorass; } else t.value = TOK.TOKxor; return;
+// removed 148 case '~': p++; if( *p == '=' ) { p++; t.value = TOK.TOKcatass; } else t.value = TOK.TOKtilde; return;
+
+
+ case '#':
+ p++;
+ Pragma();
+ continue;
+
+ default:
+ {
+ debug writefln( " default char" );
+ ubyte c = *p;
+ if( c & 0x80 )
+ {
+ uint u = decodeUTF();
+ // Check for start of unicode identifier
+ if( isUniAlpha(u) )
+ goto case_identifier;
+
+ if( u == PS || u == LS )
+ {
+ loc.linnum++;
+ p++;
+ continue;
+ }
+ }
+ if( isprint(c))
+ error("unsupported char '%s'", cast(char)c);
+ else
+ error("unsupported char 0x%02x", cast(ubyte)c);
+ p++;
+ continue;
+ }
+ }
+ }
+ }
+
+
+
+ // Parse escape sequence.
+ uint escapeSequence()
+ {
+ uint c;
+ int n;
+ int ndigits;
+
+ c = *p;
+ switch ( c )
+ {
+ case '\'':
+ case '"':
+ case '?':
+ case '\\':
+ Lconsume:
+ p++;
+ break;
+
+ case 'a': c = 7; goto Lconsume;
+ case 'b': c = 8; goto Lconsume;
+ case 'f': c = 12; goto Lconsume;
+ case 'n': c = 10; goto Lconsume;
+ case 'r': c = 13; goto Lconsume;
+ case 't': c = 9; goto Lconsume;
+ case 'v': c = 11; goto Lconsume;
+
+ case 'u':
+ ndigits = 4;
+ goto Lhex;
+ case 'U':
+ ndigits = 8;
+ goto Lhex;
+ case 'x':
+ ndigits = 2;
+ Lhex:
+ p++;
+ c = *p;
+ if( ishex(c))
+ {
+ uint v;
+ n = 0;
+ v = 0;
+ while (1)
+ {
+ if( isdigit(c))
+ c -= '0';
+ else if( islower(c))
+ c -= 'a' - 10;
+ else
+ c -= 'A' - 10;
+ v = v * 16 + c;
+ c = *++p;
+ if( ++n == ndigits)
+ break;
+ if( !ishex(c))
+ { error("escape hex sequence has %d hex digits instead of %d", n, ndigits);
+ break;
+ }
+ }
+//! if( ndigits != 2 && !utf_isValidDchar(v))
+//! error("invalid UTF character \\U%08x", v);
+ c = v;
+ }
+ else
+ error("undefined escape hex sequence \\%s\n",c);
+ break;
+
+ case '&': // named character entity
+ for( ubyte *idstart = ++p; 1; p++ )
+ {
+ switch( *p )
+ {
+ case ';':
+ //!!!
+ /+
+ c = HtmlNamedEntity(idstart, p - idstart);
+ if( c == ~0 )
+ {
+ error("unnamed character entity &%.*s;", p - idstart, idstart);
+ c = ' ';
+ }
+
+ p++;
+ +/
+ break;
+
+ default:
+ if( isalpha(*p) || (p != idstart + 1 && isdigit(*p)))
+ continue;
+ error("unterminated named entity");
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 0:
+ case 0x1a: // end of file
+ c = '\\';
+ break;
+
+ default:
+ if( isoctal(c) )
+ {
+ ubyte v;
+ n = 0;
+ do
+ {
+ v = v * 8 + (c - '0');
+ c = *++p;
+ } while (++n < 3 && isoctal(c));
+ c = v;
+ }
+ else
+ error("undefined escape sequence \\%s\n",c);
+ break;
+ }
+ return c;
+ }
+
+ /**************************************
+ */
+
+ TOK wysiwygStringConstant( Token *t, int tc )
+ {
+ uint c;
+ Loc start = loc;
+
+ p++;
+ stringbuffer.offset = 0;
+ while (1)
+ {
+ c = *p++;
+ switch( c )
+ {
+ case '\n':
+ loc.linnum++;
+ break;
+
+ case '\r':
+ if( *p == '\n')
+ continue; // ignore
+ c = '\n'; // treat EndOfLine as \n character
+ loc.linnum++;
+ break;
+
+ case 0:
+ case 0x1a:
+ error("unterminated string constant starting at %s", start.toChars());
+ t.ustring = "";
+ t.postfix = 0;
+ return TOK.TOKstring;
+
+ case '"':
+ case '`':
+ if( c == tc)
+ {
+// t.len = stringbuffer.offset;
+ stringbuffer.write(cast(byte)0);
+ t.ustring = stringbuffer.toString;
+// t.ustring = (ubyte *)mem.malloc(stringbuffer.offset);
+// memcpy(t.ustring, stringbuffer.data, stringbuffer.offset);
+ stringPostfix(t);
+ return TOK.TOKstring;
+ }
+ break;
+
+ default:
+ if( c & 0x80)
+ {
+ p--;
+ uint u = decodeUTF();
+ p++;
+ if( u == PS || u == LS)
+ loc.linnum++;
+ stringbuffer.write(u);
+ continue;
+ }
+ break;
+ }
+ stringbuffer.write(c);
+ }
+ }
+
+ /**************************************
+ * Lex hex strings:
+ * x"0A ae 34FE BD"
+ */
+
+ TOK hexStringConstant(Token *t)
+ {
+ uint c;
+ Loc start = loc;
+ uint n = 0;
+ uint v;
+
+ p++;
+ stringbuffer.offset = 0;
+ while (1)
+ {
+ c = *p++;
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ continue; // skip white space
+
+ case '\r':
+ if( *p == '\n')
+ continue; // ignore
+ // Treat isolated '\r' as if it were a '\n'
+ case '\n':
+ loc.linnum++;
+ continue;
+
+ case 0:
+ case 0x1a:
+ error("unterminated string constant starting at %s", start.toChars());
+ t.ustring = "";
+ t.postfix = 0;
+ return TOK.TOKstring;
+
+ case '"':
+ if( n & 1 )
+ {
+ error("odd number (%d) of hex characters in hex string", n);
+ stringbuffer.write(v);
+ }
+// t.len = stringbuffer.offset;
+// stringbuffer.write(cast(byte)0);
+ t.ustring = stringbuffer.toString;
+// t.ustring = (ubyte *)mem.malloc(stringbuffer.offset);
+// memcpy(t.ustring, stringbuffer.data, stringbuffer.offset);
+ stringPostfix(t);
+ return TOK.TOKstring;
+
+ default:
+ if( c >= '0' && c <= '9')
+ c -= '0';
+ else if( c >= 'a' && c <= 'f')
+ c -= 'a' - 10;
+ else if( c >= 'A' && c <= 'F')
+ c -= 'A' - 10;
+ else if( c & 0x80)
+ {
+ p--;
+ uint u = decodeUTF();
+ p++;
+ if( u == PS || u == LS)
+ loc.linnum++;
+ else
+ error("non-hex character \\u%x", u);
+ }
+ else
+ error("non-hex character '%s'", c);
+ if( n & 1)
+ {
+ v = (v << 4) | c;
+ stringbuffer.write(v);
+ }
+ else
+ v = c;
+ n++;
+ break;
+ }
+ }
+ }
+
+ /**************************************
+ */
+
+ TOK escapeStringConstant(Token *t, int wide)
+ {
+ uint c;
+ Loc start = loc;
+ p++;
+ stringbuffer.offset = 0;
+ // debug writefln( "escape string constant: %s", std.string.toString( cast(char*)p ) );
+ while( 1 )
+ {
+ c = *p++;
+ switch( c )
+ {
+ case '\\':
+ switch (*p)
+ {
+ case 'u':
+ case 'U':
+ case '&':
+ c = escapeSequence();
+ stringbuffer.write(c);
+ continue;
+
+ default:
+ c = escapeSequence();
+ break;
+ }
+ break;
+
+ case '\n':
+ loc.linnum++;
+ break;
+
+ case '\r':
+ if( *p == '\n')
+ continue; // ignore
+ c = '\n'; // treat EndOfLine as \n character
+ loc.linnum++;
+ break;
+
+ case '"':
+// writefln( "end of string: ", stringbuffer.toString );
+ t.ustring = stringbuffer.toString().dup;
+ // t.len = stringbuffer.offset;
+ // stringbuffer.write(cast(byte)0);
+ // t.ustring = (ubyte *)mem.malloc(stringbuffer.offset);
+ // memcpy(t.ustring, stringbuffer.data, stringbuffer.offset);
+ stringPostfix(t);
+
+ return TOK.TOKstring;
+
+ case 0:
+ case 0x1a:
+ p--;
+ error("unterminated string constant starting at %s", start.toChars());
+ t.ustring = "";
+// t.len = 0;
+ t.postfix = 0;
+ return TOK.TOKstring;
+
+ default:
+ if( c & 0x80 )
+ {
+ p--;
+ c = decodeUTF();
+ if( c == LS || c == PS )
+ {
+ c = '\n';
+ loc.linnum++;
+ }
+ p++;
+ stringbuffer.write(cast(char)c);
+ continue;
+ }
+ break;
+ }
+ stringbuffer.write(cast(char)c);
+// writefln( stringbuffer.toString );
+ }
+ }
+
+ //**************************************
+ TOK charConstant(Token *t, int wide)
+ {
+ uint c;
+ TOK tk = TOK.TOKcharv;
+ //printf("Lexer.charConstant\n");
+ p++;
+ c = *p++;
+ switch( c )
+ {
+ case '\\':
+ switch (*p)
+ {
+ case 'u':
+ t.uns64value = escapeSequence();
+ tk = TOK.TOKwcharv;
+ break;
+
+ case 'U':
+ case '&':
+ t.uns64value = escapeSequence();
+ tk = TOK.TOKdcharv;
+ break;
+
+ default:
+ t.uns64value = escapeSequence();
+ break;
+ }
+ break;
+
+ case '\n':
+ L1:
+ loc.linnum++;
+ case '\r':
+ case 0:
+ case 0x1a:
+ case '\'':
+ error("unterminated character constant");
+ return tk;
+
+ default:
+ if( c & 0x80)
+ {
+ p--;
+ c = decodeUTF();
+ p++;
+ if( c == LS || c == PS )
+ goto L1;
+ if( c < 0xd800 || (c >= 0xe000 && c < 0xfffe))
+ tk = TOK.TOKwcharv;
+ else
+ tk = TOK.TOKdcharv;
+ }
+ t.uns64value = c;
+ break;
+ }
+
+ if( *p != '\'' )
+ {
+ error("unterminated character constant");
+ return tk;
+ }
+ p++;
+ return tk;
+ }
+
+ // Get postfix of string literal.
+ void stringPostfix(Token *t)
+ {
+ switch( *p )
+ {
+ case 'c':
+ case 'w':
+ case 'd':
+ t.postfix = *p;
+ p++;
+ break;
+
+ default:
+ t.postfix = 0;
+ break;
+ }
+ }
+
+ /***************************************
+ * Read \u or \U unicode sequence
+ * Input:
+ * u 'u' or 'U'
+ */
+ /*
+ uint Wchar(uint u)
+ {
+ uint value;
+ uint n;
+ ubyte c;
+ uint nchars;
+
+ nchars = (u == 'U') ? 8 : 4;
+ value = 0;
+ for (n = 0; 1; n++)
+ {
+ ++p;
+ if( n == nchars)
+ break;
+ c = *p;
+ if( !ishex(c))
+ {
+ error("\\%s sequence must be followed by %d hex characters", u, nchars);
+ break;
+ }
+ if( isdigit(c))
+ c -= '0';
+ else if( islower(c))
+ c -= 'a' - 10;
+ else
+ c -= 'A' - 10;
+ value <<= 4;
+ value |= c;
+ }
+ return value;
+ }
+ */
+
+ /**************************************
+ * Read in a number.
+ * If it's an integer, store it in tok.TKutok.Vlong.
+ * integers can be decimal, octal or hex
+ * Handle the suffixes U, UL, LU, L, etc.
+ * If it's double, store it in tok.TKutok.Vdouble.
+ * Returns:
+ * TKnum
+ * TKdouble,...
+ */
+
+ TOK number(Token *t)
+ {
+ //debug writefln("Lexer.number()");
+ // We use a state machine to collect numbers
+ enum STATE
+ {
+ STATE_initial,
+ STATE_0,
+ STATE_decimal,
+ STATE_octal,
+ STATE_octale,
+ STATE_hex,
+ STATE_binary,
+ STATE_hex0,
+ STATE_binary0,
+ STATE_hexh,
+ STATE_error
+ }
+
+ enum FLAGS
+ {
+ FLAGS_decimal = 1, // decimal
+ FLAGS_unsigned = 2, // u or U suffix
+ FLAGS_long = 4, // l or L suffix
+ }
+ FLAGS flags = FLAGS.FLAGS_decimal;
+
+ int i;
+ TOK result;
+ int base;
+ stringbuffer.offset = 0;
+// stringbuffer.data = null;
+ STATE state = STATE.STATE_initial;
+ ubyte* start = p;
+
+ TOK _isreal()
+ {
+ p = start;
+ return inreal(t);
+ }
+
+ while( true )
+ {
+ char c = cast(char)*p;
+ switch( state )
+ {
+ case STATE.STATE_initial: // opening state
+ if( c == '0' )
+ state = STATE.STATE_0;
+ else
+ state = STATE.STATE_decimal;
+ break;
+
+ case STATE.STATE_0:
+ flags = cast(FLAGS) (flags & ~FLAGS.FLAGS_decimal);
+ switch (c)
+ {
+ // #if ZEROH
+// case 'H': // 0h
+// case 'h':
+// goto hexh;
+ // #endif
+ case 'X':
+ case 'x':
+ state = STATE.STATE_hex0;
+ break;
+
+ case '.':
+ if( p[1] == '.') // .. is a separate token
+ goto done;
+ case 'i':
+ case 'f':
+ case 'F':
+ goto _Real;
+ // #if ZEROH
+// case 'E':
+// case 'e':
+// goto case_hex;
+ // #endif
+ case 'B':
+ case 'b':
+ state = STATE.STATE_binary0;
+ break;
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ state = STATE.STATE_octal;
+ break;
+
+ // #if ZEROH
+// case '8': case '9': case 'A':
+// case 'C': case 'D': case 'F':
+// case 'a': case 'c': case 'd': case 'f':
+// case_hex:
+// state = STATE.STATE_hexh;
+// break;
+ // #endif
+ case '_':
+ state = STATE.STATE_octal;
+ p++;
+ continue;
+
+ default:
+ goto done;
+ }
+ break;
+
+ case STATE.STATE_decimal: // reading decimal number
+
+ // if its not a digit - decimal complete or not a decimal
+ if( !isdigit( c ) )
+ {
+// debug writefln( "\tnon-digit( %s )", c );
+ // #if ZEROH
+// if( ishex(c) || c == 'H' || c == 'h' )
+// goto hexh;
+ // #endif
+ //! wtf ?
+ // ignore embedded _
+ if( c == '_' )
+ {
+ p++;
+ continue;
+ }
+
+ // check decimal point - make real
+ if( c == '.' && p[1] != '.' )
+ goto _Real;
+
+ // check for mantra - make real
+ if( c == 'i' || c == 'f' || c == 'F' || c == 'e' || c == 'E' )
+ {
+ _Real: // It's a real number. Back up and rescan as a real
+ p = start;
+ return inreal(t);
+ }
+
+ goto done;
+ }
+ break;
+
+ case STATE.STATE_hex0: // reading hex number
+ case STATE.STATE_hex:
+ if( !ishex(c) )
+ {
+ if( c == '_') // ignore embedded _
+ {
+ p++;
+ continue;
+ }
+ if( c == '.' && p[1] != '.' )
+ goto _Real;
+ if( c == 'P' || c == 'p' || c == 'i' )
+ goto _Real;
+ if( state == STATE.STATE_hex0 )
+ error("Hex digit expected, not '%s'", c);
+ goto done;
+ }
+ state = STATE.STATE_hex;
+ break;
+
+ // #if ZEROH
+// hexh:
+// state = STATE.STATE_hexh;
+//
+// case STATE.STATE_hexh: // parse numbers like 0FFh
+// if( !ishex(c))
+// {
+// if( c == 'H' || c == 'h')
+// {
+// p++;
+// base = 16;
+// goto done;
+// }
+// else
+// {
+// // Check for something like 1E3 or 0E24
+// if( memchr(stringbuffer.data.ptr, 'E', stringbuffer.offset) || memchr( stringbuffer.data.ptr, 'e', stringbuffer.offset))
+// goto _Real;
+// error("Hex digit expected, not '%s'", c);
+// goto done;
+// }
+// }
+// break;
+ // #endif
+
+ case STATE.STATE_octal: // reading octal number
+ case STATE.STATE_octale: // reading octal number with non-octal digits
+ if( !isoctal(c) )
+ {
+// #if ZEROH
+// if( ishex(c) || c == 'H' || c == 'h' )
+// goto hexh;
+// #endif
+ if( c == '_' ) // ignore embedded _
+ {
+ p++;
+ continue;
+ }
+ if( c == '.' && p[1] != '.' )
+ goto _Real;
+ if( c == 'i' )
+ goto _Real;
+ if( isdigit(c) )
+ state = STATE.STATE_octale;
+ else
+ goto done;
+ }
+ break;
+
+ case STATE.STATE_binary0: // starting binary number
+ case STATE.STATE_binary: // reading binary number
+ if( c != '0' && c != '1')
+ {
+ // #if ZEROH
+// if( ishex(c) || c == 'H' || c == 'h' )
+// goto hexh;
+ // #endif
+ if( c == '_' ) // ignore embedded _
+ {
+ p++;
+ continue;
+ }
+ if( state == STATE.STATE_binary0 )
+ {
+ error("binary digit expected");
+ state = STATE.STATE_error;
+ break;
+ }
+ else
+ goto done;
+ }
+ state = STATE.STATE_binary;
+ break;
+
+ case STATE.STATE_error: // for error recovery
+ if( !isdigit(c) ) // scan until non-digit
+ goto done;
+ break;
+
+ default:
+ assert(0);
+ }
+ stringbuffer.write(cast(char)c);
+ p++;
+ }
+ done:
+ stringbuffer.write( cast(char)0 ); // terminate string
+
+// debug writefln( "\tdigit complete( %s )", stringbuffer.toString );
+
+ if( state == STATE.STATE_octale )
+ error("Octal digit expected");
+
+ uinteger_t n; // unsigned >=64 bit integer type
+
+ if( stringbuffer.offset == 2 && ( state == STATE.STATE_decimal || state == STATE.STATE_0 ) )
+ n = stringbuffer.data[0] - '0';
+ else
+ {
+ // Convert string to integer
+ char* p = cast(char*)stringbuffer.data.ptr;
+ int r = 10;
+ int d;
+ if( *p == '0' )
+ {
+ if( p[1] == 'x' || p[1] == 'X')
+ {
+ // "0x#"
+ p += 2;
+ r = 16;
+ }
+ else if( p[1] == 'b' || p[1] == 'B')
+ {
+ // "0b#" - binary
+ p += 2;
+ r = 2;
+ }
+ else if( isdigit(p[1]))
+ {
+ p += 1;
+ r = 8;
+ }
+ }
+
+ n = 0;
+
+ while( true )
+ {
+ if( *p >= '0' && *p <= '9' )
+ d = *p - '0';
+ else if( *p >= 'a' && *p <= 'z' )
+ d = *p - 'a' + 10;
+ else if( *p >= 'A' && *p <= 'Z' )
+ d = *p - 'A' + 10;
+ else
+ break;
+
+ if( d >= r )
+ break;
+
+ if( n * r + d < n)
+ {
+ error( "integer overflow" );
+ break;
+ }
+
+ n = n * r + d;
+ p++;
+ }
+
+ // if n needs more than 64 bits
+ if( n.sizeof > 8 && n > 0xffffffffffffffffL )
+ error("integer overflow");
+ }
+
+ // Parse trailing 'u', 'U', 'l' or 'L' in any combination
+ while( true )
+ {
+ ubyte f;
+ switch( *p )
+ {
+ case 'U':
+ case 'u':
+ f = FLAGS.FLAGS_unsigned;
+ goto L1;
+ case 'L':
+ case 'l':
+ f = FLAGS.FLAGS_long;
+ L1:
+ p++;
+ if( flags & f )
+ error("unrecognized token");
+ flags = cast(FLAGS) (flags | f);
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ switch ( flags )
+ {
+ case 0:
+ /* Octal or Hexadecimal constant.
+ * First that fits: int, uint, long, ulong
+ */
+ if( n & 0x8000000000000000L )
+ result = TOK.TOKuns64v;
+ else if( n & 0xffffffff00000000L )
+ result = TOK.TOKint64v;
+ else if( n & 0x80000000 )
+ result = TOK.TOKuns32v;
+ else
+ result = TOK.TOKint32v;
+ break;
+
+ case FLAGS.FLAGS_decimal:
+ /* First that fits: int, long, long long
+ */
+ if( n & 0x8000000000000000L )
+ {
+ error("signed integer overflow");
+ result = TOK.TOKuns64v;
+ }
+ else if( n & 0xffffffff80000000L )
+ result = TOK.TOKint64v;
+ else
+ result = TOK.TOKint32v;
+ break;
+
+ case FLAGS.FLAGS_unsigned:
+ case FLAGS.FLAGS_decimal | FLAGS.FLAGS_unsigned:
+ /* First that fits: uint, ulong
+ */
+ if( n & 0xffffffff00000000L )
+ result = TOK.TOKuns64v;
+ else
+ result = TOK.TOKuns32v;
+ break;
+
+ case FLAGS.FLAGS_decimal | FLAGS.FLAGS_long:
+ if( n & 0x8000000000000000L )
+ {
+ error("signed integer overflow");
+ result = TOK.TOKuns64v;
+ }
+ else
+ result = TOK.TOKint64v;
+ break;
+
+ case FLAGS.FLAGS_long:
+ if( n & 0x8000000000000000L )
+ result = TOK.TOKuns64v;
+ else
+ result = TOK.TOKint64v;
+ break;
+
+ case FLAGS.FLAGS_unsigned | FLAGS.FLAGS_long:
+ case FLAGS.FLAGS_decimal | FLAGS.FLAGS_unsigned | FLAGS.FLAGS_long:
+ result = TOK.TOKuns64v;
+ break;
+
+ default:
+ debug writefln("%x",flags);
+ assert(0);
+ }
+ t.uns64value = n;
+ return result;
+ }
+
+ /**************************************
+ * Read in characters, converting them to real.
+ * Bugs:
+ * Exponent overflow not detected.
+ * Too much requested precision is not detected.
+ */
+
+ TOK inreal(Token *t)
+ {
+ int dblstate;
+ uint c;
+ char hex; // is this a hexadecimal-floating-constant?
+ TOK result;
+
+ //printf("Lexer.inreal()\n");
+ stringbuffer.offset = 0;
+ dblstate = 0;
+ hex = 0;
+ Lnext:
+ while (1)
+ {
+ // Get next char from input
+ c = *p++;
+ //printf("dblstate = %d, c = '%s'\n", dblstate, c);
+ while (1)
+ {
+ switch (dblstate)
+ {
+ case 0: // opening state
+ if( c == '0')
+ dblstate = 9;
+ else if( c == '.')
+ dblstate = 3;
+ else
+ dblstate = 1;
+ break;
+
+ case 9:
+ dblstate = 1;
+ if( c == 'X' || c == 'x')
+ {
+ hex++;
+ break;
+ }
+ case 1: // digits to left of .
+ case 3: // digits to right of .
+ case 7: // continuing exponent digits
+ if( !isdigit(c) && !(hex && isxdigit(c)))
+ {
+ if( c == '_')
+ goto Lnext; // ignore embedded '_'
+ dblstate++;
+ continue;
+ }
+ break;
+
+ case 2: // no more digits to left of .
+ if( c == '.')
+ {
+ dblstate++;
+ break;
+ }
+ case 4: // no more digits to right of .
+ if( (c == 'E' || c == 'e') || hex && (c == 'P' || c == 'p'))
+ {
+ dblstate = 5;
+ hex = 0; // exponent is always decimal
+ break;
+ }
+ if( hex)
+ error("binary-exponent-part required");
+ goto done;
+
+ case 5: // looking immediately to right of E
+ dblstate++;
+ if( c == '-' || c == '+')
+ break;
+ case 6: // 1st exponent digit expected
+ if( !isdigit(c))
+ error("exponent expected");
+ dblstate++;
+ break;
+
+ case 8: // past end of exponent digits
+ goto done;
+ }
+ break;
+ }
+ stringbuffer.write(c);
+ }
+ done:
+ p--;
+
+ stringbuffer.write(cast(byte)0);
+
+// #if _WIN32 && __DMC__
+ char *save = __locale_decpoint;
+ __locale_decpoint = ".";
+// #endif
+ t.float80value = strtold(cast(char *)stringbuffer.data.ptr, null);
+ errno = 0;
+ switch( *p )
+ {
+ case 'F':
+ case 'f':
+ strtof(cast(char *)stringbuffer.data.ptr, null);
+ result = TOK.TOKfloat32v;
+ p++;
+ break;
+
+ default:
+ strtod(cast(char *)stringbuffer.data.ptr, null);
+ result = TOK.TOKfloat64v;
+ break;
+
+ case 'L':
+ case 'l':
+ result = TOK.TOKfloat80v;
+ p++;
+ break;
+ }
+ if( *p == 'i' || *p == 'I')
+ {
+ p++;
+ switch( result )
+ {
+ case TOK.TOKfloat32v:
+ result = TOK.TOKimaginary32v;
+ break;
+ case TOK.TOKfloat64v:
+ result = TOK.TOKimaginary64v;
+ break;
+ case TOK.TOKfloat80v:
+ result = TOK.TOKimaginary80v;
+ break;
+ }
+ }
+// #if _WIN32 && __DMC__
+ __locale_decpoint = save;
+// #endif
+ if( errno == ERANGE)
+ error("number is not representable");
+ return result;
+ }
+
+
+
+
+ /*********************************************
+ * Do pragma.
+ * Currently, the only pragma supported is:
+ * #line linnum [filespec]
+ */
+
+ void Pragma()
+ {
+ Token tok;
+ int linnum;
+ char[] filespec;
+ Loc loc = this.loc;
+
+ scan(&tok);
+
+ if( tok.value != TOK.TOKidentifier || tok.identifier != Id.line )
+ goto Lerr;
+
+ scan(&tok);
+ if( tok.value == TOK.TOKint32v || tok.value == TOK.TOKint64v )
+ linnum = tok.uns64value - 1;
+ else
+ goto Lerr;
+
+ while (1)
+ {
+ switch (*p)
+ {
+ case 0:
+ case 0x1a:
+ case '\n':
+ Lnewline:
+ this.loc.linnum = linnum;
+ if( filespec.length )
+ this.loc.filename = filespec;
+ return;
+
+ case '\r':
+ p++;
+ if( *p != '\n')
+ { p--;
+ goto Lnewline;
+ }
+ continue;
+
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ p++;
+ continue; // skip white space
+
+ case '_':
+ if( mod && memcmp(p, cast(char*)"__FILE__", 8) == 0)
+ {
+ p += 8;
+//! filespec = mem.strdup(loc.filename ? loc.filename : mod.identifier.toChars());
+ }
+ continue;
+
+ case '"':
+ if( filespec )
+ goto Lerr;
+ stringbuffer.offset = 0;
+ p++;
+ while (1)
+ {
+ uint c;
+ c = *p;
+ switch (c)
+ {
+ case '\n':
+ case '\r':
+ case 0:
+ case 0x1a:
+ goto Lerr;
+
+ case '"':
+ stringbuffer.write(cast(byte)0);
+ // filespec = mem.strdup((char *)stringbuffer.data);
+ filespec = stringbuffer.toString.dup;
+ p++;
+ break;
+
+ default:
+ if( c & 0x80 )
+ {
+ uint u = decodeUTF();
+ if( u == PS || u == LS )
+ goto Lerr;
+ }
+ stringbuffer.write(c);
+ p++;
+ continue;
+ }
+ break;
+ }
+ continue;
+
+ default:
+ if( *p & 0x80 )
+ {
+ uint u = decodeUTF();
+ if( u == PS || u == LS)
+ goto Lnewline;
+ }
+ goto Lerr;
+ }
+ }
+
+ Lerr:
+ errorLoc(loc, "#line integer [\"filespec\"]\\n expected");
+ }
+
+
+
+ /***************************************************
+ * Parse doc comment embedded between t.ptr and p.
+ * Remove trailing blanks and tabs from lines.
+ * Replace all newlines with \n.
+ * Remove leading comment character from each line.
+ * Decide if it's a lineComment or a blockComment.
+ * Append to previous one for this token.
+ */
+
+ void getDocComment( Token *t, uint lineComment )
+ {
+ auto OutBuffer buf = new OutBuffer;
+ ubyte ct = t.ptr[2];
+ ubyte *q = t.ptr + 3; // start of comment text
+ int linestart = 0;
+
+ ubyte *qend = p;
+
+ if( ct == '*' || ct == '+')
+ qend -= 2;
+
+ // Scan over initial row of ****'s or ++++'s or ////'s
+ for (; q < qend; q++)
+ {
+ if( *q != ct)
+ break;
+ }
+
+ // Remove trailing row of ****'s or ++++'s
+ if( ct != '/')
+ {
+ for (; q < qend; qend--)
+ {
+ if( qend[-1] != ct)
+ break;
+ }
+ }
+
+ for (; q < qend; q++)
+ {
+ ubyte c = *q;
+
+ switch (c)
+ {
+ case '*':
+ case '+':
+ if( linestart && c == ct)
+ { linestart = 0;
+ // Trim preceding whitespace up to preceding \n
+ while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+ buf.offset--;
+ continue;
+ }
+ break;
+
+ case ' ':
+ case '\t':
+ break;
+
+ case '\r':
+ if( q[1] == '\n')
+ continue; // skip the \r
+ goto Lnewline;
+
+ default:
+ if( c == 226)
+ {
+ // If LS or PS
+ if( q[1] == 128 &&
+ (q[2] == 168 || q[2] == 169))
+ {
+ q += 2;
+ goto Lnewline;
+ }
+ }
+ linestart = 0;
+ break;
+
+ Lnewline:
+ c = '\n'; // replace all newlines with \n
+ case '\n':
+ linestart = 1;
+
+ // Trim trailing whitespace
+ while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+ buf.offset--;
+
+ break;
+ }
+ buf.write(c);
+ }
+
+ // Always end with a newline
+ if( !buf.offset || buf.data[buf.offset - 1] != '\n' )
+ buf.writenl();
+
+ //buf.write(cast(char)0);
+
+ // It's a line comment if the start of the doc comment comes
+ // after other non-whitespace on the same line.
+// ubyte** dc = (lineComment && anyToken)
+// ? &t.lineComment
+// : &t.blockComment;
+
+ char[] dc = (lineComment && anyToken) ? t.lineComment : t.blockComment;
+
+ // Combine with previous doc comment, if any
+ if( dc.length )
+ dc = combineComments( dc, buf.toString().dup );
+ else
+ dc = buf.toString().dup;
+
+// writefln( dc );
+
+ if( lineComment && anyToken )
+ t.lineComment = dc;
+ else
+ t.blockComment = dc;
+
+ }
+
+}
+
+// character maps
+static ubyte[256] cmtable;
+
+const int CMoctal = 0x1;
+const int CMhex = 0x2;
+const int CMidchar = 0x4;
+
+ubyte isoctal (ubyte c) { return cmtable[c] & CMoctal; }
+ubyte ishex (ubyte c) { return cmtable[c] & CMhex; }
+ubyte isidchar(ubyte c) { return cmtable[c] & CMidchar; }
+
+static void cmtable_init()
+{
+ for( uint c = 0; c < cmtable.length; c++ )
+ {
+ if( '0' <= c && c <= '7' )
+ cmtable[c] |= CMoctal;
+ if( isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') )
+ cmtable[c] |= CMhex;
+ if( isalnum(c) || c == '_' )
+ cmtable[c] |= CMidchar;
+ }
+}
+
+
+/+
+struct StringValue
+{
+ union
+ {
+ int intvalue;
+ void *ptrvalue;
+ dchar *string;
+ }
+
+ char[] lstring;
+}
+#define CASE_BASIC_TYPES
+ case TOKwchar: case TOKdchar:
+ case TOKbit: case TOKbool: case TOKchar:
+ case TOKint8: case TOKuns8:
+ case TOKint16: case TOKuns16:
+ case TOKint32: case TOKuns32:
+ case TOKint64: case TOKuns64:
+ case TOKfloat32: case TOKfloat64: case TOKfloat80:
+ case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+ case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+ case TOKvoid:
+
+#define CASE_BASIC_TYPES_X(t) \
+ case TOKvoid: t = Type::tvoid; goto LabelX; \
+ case TOKint8: t = Type::tint8; goto LabelX; \
+ case TOKuns8: t = Type::tuns8; goto LabelX; \
+ case TOKint16: t = Type::tint16; goto LabelX; \
+ case TOKuns16: t = Type::tuns16; goto LabelX; \
+ case TOKint32: t = Type::tint32; goto LabelX; \
+ case TOKuns32: t = Type::tuns32; goto LabelX; \
+ case TOKint64: t = Type::tint64; goto LabelX; \
+ case TOKuns64: t = Type::tuns64; goto LabelX; \
+ case TOKfloat32: t = Type::tfloat32; goto LabelX; \
+ case TOKfloat64: t = Type::tfloat64; goto LabelX; \
+ case TOKfloat80: t = Type::tfloat80; goto LabelX; \
+ case TOKimaginary32: t = Type::timaginary32; goto LabelX; \
+ case TOKimaginary64: t = Type::timaginary64; goto LabelX; \
+ case TOKimaginary80: t = Type::timaginary80; goto LabelX; \
+ case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \
+ case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \
+ case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \
+ case TOKbit: t = Type::tbit; goto LabelX; \
+ case TOKchar: t = Type::tchar; goto LabelX; \
+ case TOKwchar: t = Type::twchar; goto LabelX; \
+ case TOKdchar: t = Type::tdchar; goto LabelX; \
+ LabelX
++/