c++11 style raw-string support

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4582 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-01-15 02:13:58 +00:00
parent c52a75aea0
commit 9a38addfaf

View file

@ -1321,287 +1321,356 @@ void QCC_PR_LexString (void)
int c; int c;
int len; int len;
char *end, *cnst; char *end, *cnst;
int raw;
char rawdelim[64];
int texttype=0; int texttype;
pbool first = true;
len = 0; for(;;)
pr_file_p++;
do
{ {
c = *pr_file_p++; raw = 0;
if (!c) texttype = 0;
QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
if (c=='\n') QCC_PR_LexWhitespace(false);
QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "newline inside quote");
if (c=='\\') if (*pr_file_p == 'R' && pr_file_p[1] == '\"')
{ // escape char {
/*R"delim(fo
o)delim" -> "fo\no"
the []
*/
raw = 1;
pr_file_p+=2;
while (1)
{
c = *pr_file_p++;
if (c == '(')
{
rawdelim[0] = ')';
break;
}
if (!c || raw >= sizeof(rawdelim)-1)
QCC_PR_ParseError (ERR_EOF, "EOF while parsing raw string delimiter. Expected: R\"delim(string)delim\"");
rawdelim[raw++] = c;
}
rawdelim[raw++] = '\"';
}
else if (*pr_file_p == '\"')
pr_file_p++;
else if (first)
QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Expected string constant");
else
break;
first = false;
len = 0;
for(;;)
{
c = *pr_file_p++; c = *pr_file_p++;
if (!c) if (!c)
QCC_PR_ParseError (ERR_EOF, "EOF inside quote"); QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
if (c == 'n')
c = '\n'; //these two conditions are generally part of the C preprocessor.
else if (c == 'r') if (c == '\\' && *pr_file_p == '\r' && pr_file_p[1] == '\n')
c = '\r'; { //dos format
else if (c == '"') pr_file_p += 2;
c = '"'; pr_source_line++;
else if (c == 't')
c = '\t'; //tab
else if (c == 'a')
c = '\a'; //bell
else if (c == 'v')
c = '\v'; //vertical tab
else if (c == 'f')
c = '\f'; //form feed
else if (c == 's' || c == 'b')
{
texttype ^= 128;
continue; continue;
} }
//else if (c == 'b') if (c == '\\' && (*pr_file_p == '\r' || pr_file_p[1] == '\n'))
// c = '\b'; { //mac + unix format
else if (c == '[') pr_file_p += 1;
c = 16; //quake specific pr_source_line++;
else if (c == ']')
c = 17; //quake specific
else if (c == '{')
{
int d;
c = 0;
while ((d = *pr_file_p++) != '}')
{
c = c * 10 + d - '0';
if (d < '0' || d > '9' || c > 255)
QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
}
}
else if (c == '.')
c = 0x1c | texttype;
else if (c == '<')
c = 29;
else if (c == '-')
c = 30;
else if (c == '>')
c = 31;
else if (c == 'u' || c == 'U')
{
//lower case u specifies exactly 4 nibbles.
//upper case U specifies variable length. terminate with a double-doublequote pair, or some other non-hex char.
int count = 0;
unsigned long d;
unsigned long unicode;
unicode = 0;
for(;;)
{
d = (unsigned char)*pr_file_p;
if (d >= '0' && d <= '9')
unicode = (unicode*16) + (d - '0');
else if (d >= 'A' && d <= 'F')
unicode = (unicode*16) + (d - 'A') + 10;
else if (d >= 'a' && d <= 'f')
unicode = (unicode*16) + (d - 'a') + 10;
else
break;
count++;
pr_file_p++;
}
if (!count || ((c=='u')?(count!=4):(count>8)) || unicode > 0x10FFFFu) //RFC 3629 imposes the same limit as UTF-16 surrogate pairs.
QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad character code");
//figure out the count of bytes required to encode this char
count = 1;
d = 0x7f;
while (unicode > d)
{
count++;
d = (d<<5) | 0x1f;
}
//error if needed
if (len+count >= sizeof(pr_token))
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
//output it.
if (count == 1)
pr_token[len++] = (unsigned char)(c&0x7f);
else
{
c = count*6;
pr_token[len++] = (unsigned char)((unicode>>c)&(0x0000007f>>count)) | (0xffffff00 >> count);
do
{
c = c-6;
pr_token[len++] = (unsigned char)((unicode>>c)&0x3f) | 0x80;
}
while(c);
}
continue; continue;
} }
else if (c == 'x' || c == 'X')
if (raw)
{ {
int d; //raw strings contain very little parsing. just delimiter and \NL support.
c = 0; if (c == rawdelim[0] && !strncmp(pr_file_p, rawdelim+1, raw-1))
{
pr_file_p += raw-1;
break;
}
d = (unsigned char)*pr_file_p++; //make sure line numbers are correct
if (d >= '0' && d <= '9') if (c == '\r' && *pr_file_p != '\n')
c += d - '0'; pr_source_line++; //mac
else if (d >= 'A' && d <= 'F') if (c == '\n') //dos/unix
c += d - 'A' + 10; pr_source_line++;
else if (d >= 'a' && d <= 'f')
c += d - 'a' + 10;
else
QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
c *= 16;
d = (unsigned char)*pr_file_p++;
if (d >= '0' && d <= '9')
c += d - '0';
else if (d >= 'A' && d <= 'F')
c += d - 'A' + 10;
else if (d >= 'a' && d <= 'f')
c += d - 'a' + 10;
else
QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
}
else if (c == '\\')
c = '\\';
else if (c == '\'')
c = '\'';
else if (c >= '0' && c <= '9') //WARNING: This is not octal, but uses 'yellow' numbers instead (as on hud).
c = 18 + c - '0';
else if (c == '\r')
{ //sigh
c = *pr_file_p++;
if (c != '\n')
QCC_PR_ParseWarning(WARN_HANGINGSLASHR, "Hanging \\\\\r");
pr_source_line++;
}
else if (c == '\n')
{ //sigh
pr_source_line++;
} }
else else
QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "Unknown escape char %c", c);
}
else if (c=='\"')
{
if (len >= sizeof(pr_immediate_string)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_immediate_string)-1);
QCC_PR_LexWhitespace(false);
if (*pr_file_p == '\"') //have annother go
{ {
pr_file_p++; if (c=='\n')
continue; QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "newline inside quote");
} if (c=='\\')
pr_token[len] = 0; { // escape char
pr_token_type = tt_immediate; c = *pr_file_p++;
pr_immediate_type = type_string; if (!c)
strcpy (pr_immediate_string, pr_token); QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
if (c == 'n')
if (qccwarningaction[WARN_NOTUTF8]) c = '\n';
{ else if (c == 'r')
len = 0; c = '\r';
//this doesn't do over-long checks. else if (c == '"')
for (c = 0; pr_token[c]; c++) c = '"';
{ else if (c == 't')
if (len) c = '\t'; //tab
else if (c == 'a')
c = '\a'; //bell
else if (c == 'v')
c = '\v'; //vertical tab
else if (c == 'f')
c = '\f'; //form feed
else if (c == 's' || c == 'b')
{ {
if ((pr_token[c] & 0xc0) != 0x80) texttype ^= 128;
break; continue;
len--;
} }
else if (pr_token[c] & 0x80) //else if (c == 'b')
// c = '\b';
else if (c == '[')
c = 16; //quake specific
else if (c == ']')
c = 17; //quake specific
else if (c == '{')
{ {
if (!(pr_token[c] & 0x40)) int d;
c = 0;
while ((d = *pr_file_p++) != '}')
{ {
//error. c = c * 10 + d - '0';
len = 1; if (d < '0' || d > '9' || c > 255)
break; QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
} }
else if (!(pr_token[c] & 0x20)) }
len = 2; else if (c == '.')
else if (!(pr_token[c] & 0x10)) c = 0x1c | texttype;
len = 3; else if (c == '<')
else if (!(pr_token[c] & 0x08)) c = 29;
len = 4; else if (c == '-')
else if (!(pr_token[c] & 0x04)) c = 30;
len = 5; else if (c == '>')
else if (!(pr_token[c] & 0x02)) c = 31;
len = 6; else if (c == 'u' || c == 'U')
else if (!(pr_token[c] & 0x01)) {
len = 7; //lower case u specifies exactly 4 nibbles.
//upper case U specifies variable length. terminate with a double-doublequote pair, or some other non-hex char.
int count = 0;
unsigned long d;
unsigned long unicode;
unicode = 0;
for(;;)
{
d = (unsigned char)*pr_file_p;
if (d >= '0' && d <= '9')
unicode = (unicode*16) + (d - '0');
else if (d >= 'A' && d <= 'F')
unicode = (unicode*16) + (d - 'A') + 10;
else if (d >= 'a' && d <= 'f')
unicode = (unicode*16) + (d - 'a') + 10;
else
break;
count++;
pr_file_p++;
}
if (!count || ((c=='u')?(count!=4):(count>8)) || unicode > 0x10FFFFu) //RFC 3629 imposes the same limit as UTF-16 surrogate pairs.
QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad unicode character code");
//figure out the count of bytes required to encode this char
count = 1;
d = 0x7f;
while (unicode > d)
{
count++;
d = (d<<5) | 0x1f;
}
//error if needed
if (len+count >= sizeof(pr_token))
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
//output it.
if (count == 1)
pr_token[len++] = (unsigned char)(c&0x7f);
else else
len = 8; {
c = count*6;
pr_token[len++] = (unsigned char)((unicode>>c)&(0x0000007f>>count)) | (0xffffff00 >> count);
do
{
c = c-6;
pr_token[len++] = (unsigned char)((unicode>>c)&0x3f) | 0x80;
}
while(c);
}
continue;
}
else if (c == 'x' || c == 'X')
{
int d;
c = 0;
d = (unsigned char)*pr_file_p++;
if (d >= '0' && d <= '9')
c += d - '0';
else if (d >= 'A' && d <= 'F')
c += d - 'A' + 10;
else if (d >= 'a' && d <= 'f')
c += d - 'a' + 10;
else
QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
c *= 16;
d = (unsigned char)*pr_file_p++;
if (d >= '0' && d <= '9')
c += d - '0';
else if (d >= 'A' && d <= 'F')
c += d - 'A' + 10;
else if (d >= 'a' && d <= 'f')
c += d - 'a' + 10;
else
QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
}
else if (c == '\\')
c = '\\';
else if (c == '\'')
c = '\'';
else if (c >= '0' && c <= '9') //WARNING: This is not octal, but uses 'yellow' numbers instead (as on hud).
c = 18 + c - '0';
else if (c == '\r')
{ //sigh
c = *pr_file_p++;
if (c != '\n')
QCC_PR_ParseWarning(WARN_HANGINGSLASHR, "Hanging \\\\\r");
pr_source_line++;
}
else if (c == '\n')
{ //sigh
pr_source_line++;
}
else
QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "Unknown escape char %c", c);
}
else if (c=='\"')
{
break;
}
else if (c == '#')
{
for (end = pr_file_p; ; end++)
{
if (qcc_iswhite(*end))
break;
if (*end == ')'
|| *end == '('
|| *end == '+'
|| *end == '-'
|| *end == '*'
|| *end == '/'
|| *end == '\\'
|| *end == '|'
|| *end == '&'
|| *end == '='
|| *end == '^'
|| *end == '~'
|| *end == '['
|| *end == ']'
|| *end == '\"'
|| *end == '{'
|| *end == '}'
|| *end == ';'
|| *end == ':'
|| *end == ','
|| *end == '.'
|| *end == '#')
break;
}
c = *end;
*end = '\0';
cnst = QCC_PR_CheckCompConstString(pr_file_p);
if (cnst==pr_file_p)
cnst=NULL;
*end = c;
c = '#'; //undo
if (cnst)
{
QCC_PR_ParseWarning(WARN_MACROINSTRING, "Macro expansion in string");
if (len+strlen(cnst) >= sizeof(pr_token)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
strcpy(pr_token+len, cnst);
len+=strlen(cnst);
pr_file_p = end;
continue;
} }
} }
if (len) else if (c == 0x7C && flag_acc) //reacc support... reacc is strange.
QCC_PR_ParseWarning(WARN_NOTUTF8, "String constant is not valid utf-8"); c = '\n';
else
c |= texttype;
} }
return;
if (len >= sizeof(pr_token)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
pr_token[len] = c;
len++;
} }
else if (c == '#') }
if (len > sizeof(pr_immediate_string)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_immediate_string)-1);
pr_token[len] = 0;
pr_token_type = tt_immediate;
pr_immediate_type = type_string;
strcpy (pr_immediate_string, pr_token);
if (qccwarningaction[WARN_NOTUTF8])
{
len = 0;
//this doesn't do over-long checks.
for (c = 0; pr_token[c]; c++)
{ {
for (end = pr_file_p; ; end++) if (len)
{ {
if (qcc_iswhite(*end)) if ((pr_token[c] & 0xc0) != 0x80)
break; break;
len--;
if (*end == ')'
|| *end == '('
|| *end == '+'
|| *end == '-'
|| *end == '*'
|| *end == '/'
|| *end == '\\'
|| *end == '|'
|| *end == '&'
|| *end == '='
|| *end == '^'
|| *end == '~'
|| *end == '['
|| *end == ']'
|| *end == '\"'
|| *end == '{'
|| *end == '}'
|| *end == ';'
|| *end == ':'
|| *end == ','
|| *end == '.'
|| *end == '#')
break;
} }
else if (pr_token[c] & 0x80)
c = *end;
*end = '\0';
cnst = QCC_PR_CheckCompConstString(pr_file_p);
if (cnst==pr_file_p)
cnst=NULL;
*end = c;
c = '#'; //undo
if (cnst)
{ {
QCC_PR_ParseWarning(WARN_MACROINSTRING, "Macro expansion in string"); if (!(pr_token[c] & 0x40))
{
if (len+strlen(cnst) >= sizeof(pr_token)-1) //error.
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1); len = 1;
break;
strcpy(pr_token+len, cnst); }
len+=strlen(cnst); else if (!(pr_token[c] & 0x20))
pr_file_p = end; len = 2;
continue; else if (!(pr_token[c] & 0x10))
len = 3;
else if (!(pr_token[c] & 0x08))
len = 4;
else if (!(pr_token[c] & 0x04))
len = 5;
else if (!(pr_token[c] & 0x02))
len = 6;
else if (!(pr_token[c] & 0x01))
len = 7;
else
len = 8;
} }
} }
else if (c == 0x7C && flag_acc) //reacc support... reacc is strange. if (len)
c = '\n'; QCC_PR_ParseWarning(WARN_NOTUTF8, "String constant is not valid utf-8");
else }
c |= texttype;
pr_token[len] = c;
len++;
if (len >= sizeof(pr_token)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
} while (1);
} }
#endif #endif
@ -2939,7 +3008,7 @@ void QCC_PR_Lex (void)
} }
// handle quoted strings as a unit // handle quoted strings as a unit
if (c == '\"') if (c == '\"' || (c == 'R' && pr_file_p[1] == '\"'))
{ {
QCC_PR_LexString (); QCC_PR_LexString ();
return; return;