Fix qcc crash from stray continue/break/case. Fix warnings from logicops. Recolour error/warning text output on linux.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5311 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-09-29 03:40:50 +00:00
parent fa9694a255
commit caa5be6267
6 changed files with 102 additions and 46 deletions

View File

@ -494,7 +494,9 @@ typedef struct
} QCC_sref_t;
typedef struct qcc_statement_s
{
unsigned int op;
unsigned short op;
#define STF_LOGICOP (1u<<0) //do not bother following when looking for uninitialised variables.
unsigned short flags;
QCC_sref_t a, b, c;
unsigned int linenum;
} QCC_statement_t;

View File

@ -636,6 +636,7 @@ extern pbool flag_allowuninit;
extern pbool flag_cpriority;
extern pbool flag_embedsrc;
extern pbool flag_nopragmafileline;
extern pbool flag_utf8strings;
extern pbool opt_overlaptemps;
extern pbool opt_shortenifnots;
@ -912,6 +913,25 @@ enum {
WARN_MAX
};
//ansi colour codes, for debugging stuff.
enum
{
COL_NONE, //white/regular text.
COL_ERROR, //to highlight errors
COL_WARNING, //to highlight warnings
COL_LOCATION, //to highlight file:line locations
COL_NAME, //unknown symbols.
COL_SYMBOL, //known symbols
COL_MAX
};
extern const char *qcccol[COL_MAX];
#define col_none qcccol[COL_NONE]
#define col_location qcccol[COL_LOCATION]
#define col_error qcccol[COL_ERROR]
#define col_name qcccol[COL_NAME]
#define col_warning qcccol[COL_WARNING]
#define col_symbol qcccol[COL_SYMBOL]
#define FLAG_KILLSDEBUGGERS 1
#define FLAG_ASDEFAULT 2
#define FLAG_SETINGUI 4

View File

@ -128,6 +128,7 @@ pbool flag_cpriority; //operator precidence should adhere to C standards, inste
pbool flag_allowuninit; //ignore uninitialised locals, avoiding all private locals.
pbool flag_embedsrc; //embed all source files inside the .dat (can be opened with any zip program)
pbool flag_nopragmafileline;//ignore #pragma file and #pragma line, so that I can actually read+debug xonotic's code.
pbool flag_utf8strings; //strings default to u8"" string rules.
pbool opt_overlaptemps; //reduce numpr_globals by reuse of temps. When they are not needed they are freed for reuse. The way this is implemented is better than frikqcc's. (This is the single most important optimisation)
pbool opt_assignments; //STORE_F isn't used if an operation wrote to a temp.
@ -3722,6 +3723,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
/*generate new OP_ADDRESS instruction - FIXME: the arguments may have changed since the original instruction*/
statement->op = OP_ADDRESS;
statement->flags = 0;
statement->a = statements[st].a;
statement->b = statements[st].b;
statement->c = var_c->ofs;
@ -3729,6 +3731,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
/*convert old one to an OP_LOAD*/
statements[st].op = ((*op->type_c)->type==ev_vector)?OP_LOAD_V:OP_LOAD_F;
statement->flags = 0;
// statements[st].a = statements[st].a;
// statements[st].b = statements[st].b;
// statements[st].c = statements[st].c;
@ -3805,6 +3808,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
//float pointer float
temp = QCC_GetTemp(type_float);
statement->op = OP_BITAND_F;
statement->flags = 0;
statement->a = var_c ? var_c->ofs : 0;
statement->b = var_a ? var_a->ofs : 0;
statement->c = temp->ofs;
@ -3814,6 +3818,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
statement->linenum = pr_token_line_last;
statement->op = OP_SUB_F;
statement->flags = 0;
//t = c & i
//c = c - t
@ -4155,6 +4160,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
statement->linenum = pr_token_line_last;
statement->op = op - pr_opcodes;
statement->flags = 0;
statement->a = var_a;
statement->b = var_b;
@ -4238,6 +4244,7 @@ QCC_statement_t *QCC_PR_SimpleStatement ( QCC_opcode_t *op, QCC_sref_t var_a, QC
numstatements++;
statement->op = op - pr_opcodes;
statement->flags = 0;
statement->a = var_a;
statement->b = var_b;
statement->c = var_c;
@ -4538,7 +4545,7 @@ void QCC_VerifyFormatString (const char *funcname, QCC_ref_t **arglist, unsigned
{
case 0:
if (argpos < argcount && argn_last < argcount)
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: surplus trailing arguments", funcname);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: surplus trailing arguments for format", funcname);
return;
case '%':
if(*++s == '%')
@ -9863,7 +9870,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
rhsr = QCC_PR_RefExpression (&rhsbuf, priority, exprflags | EXPR_DISALLOW_ARRAYASSIGN|EXPR_DISALLOW_COMMA);
if (conditional&1)
QCC_PR_ParseWarning(WARN_ASSIGNMENTINCONDITIONAL, "suggest parenthesis for assignment used as truth value .");
QCC_PR_ParseWarning(WARN_ASSIGNMENTINCONDITIONAL, "suggest parenthesis for assignment used as truth value");
rhsd = QCC_RefToDef(rhsr, true);
@ -10010,6 +10017,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
if (logicjump) //logic shortcut jumps to just before the if. the rhs is uninitialised if the jump was taken, but the lhs makes it deterministic.
{
logicjump->flags |= STF_LOGICOP;
logicjump->b.ofs = &statements[numstatements] - logicjump;
if (logicjump->b.ofs == 1)
numstatements--; //err, that was pointless.
@ -12163,7 +12171,7 @@ int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_def_t *
return i;
}
}
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->b.ofs > 0)
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->b.ofs > 0 && !(st->flags & STF_LOGICOP))
{
int jump = i + (int)st->b.ofs;
//check if there's an else.
@ -13027,21 +13035,20 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *typ
if (num_labels)
num_labels = 0;
if (num_cases)
{
num_cases = 0;
QCC_PR_ParseError(ERR_ILLEGALCASES, "%s: function contains illegal cases", f->name);
}
if (num_continues)
{
num_continues=0;
QCC_PR_ParseError(ERR_ILLEGALCONTINUES, "%s: function contains illegal continues", pr_scope->name);
QCC_PR_ParseError(ERR_ILLEGALCONTINUES, "%s: function contains illegal continues", f->name);
}
if (num_breaks)
{
num_breaks=0;
QCC_PR_ParseError(ERR_ILLEGALBREAKS, "%s: function contains illegal breaks", pr_scope->name);
}
if (num_cases)
{
num_cases = 0;
QCC_PR_ParseError(ERR_ILLEGALCASES, "%s: function contains illegal cases", pr_scope->name);
QCC_PR_ParseError(ERR_ILLEGALBREAKS, "%s: function contains illegal breaks", f->name);
}
//clean up the locals. remove parms from the hashtable but don't clean subscoped_away so that we can repopulate on the next accumulation

View File

@ -1577,8 +1577,7 @@ void QCC_PR_LexString (void)
char *end, *cnst;
int raw;
char rawdelim[64];
unsigned int code;
int stringtype = 0; //0 - quake output, input is 8bit. warnings when its not ascii. \u will still give utf-8 text, other chars as-is. Expect \s to screw everything up with utf-8 output.
int stringtype = flag_utf8strings?2:0; //0 - quake output, input is 8bit. warnings when its not ascii. \u will still give utf-8 text, other chars as-is. Expect \s to screw everything up with utf-8 output.
//1 - quake output, input is utf-8. due to editors not supporting it, that generally means the input (ab)uses markup.
//2 - utf-8 output, input is utf-8. welcome to the future! unfortunately not the present.
@ -1913,6 +1912,8 @@ void QCC_PR_LexString (void)
unsigned int len = stringtype?utf8_check(pr_file_p-1, &cp):0;
if (!len)
{ //invalid utf-8 encoding? don't treat it as utf-8!
if (stringtype)
QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Input string is not valid utf-8");
c |= texttype;
goto forcequake;
}
@ -1996,8 +1997,9 @@ forcebyte:
memcpy(pr_immediate_string, pr_token, len+1);
pr_immediate_strlen = len;
if (qccwarningaction[WARN_NOTUTF8])
/*if (qccwarningaction[WARN_NOTUTF8] && stringtype != 1)
{
unsigned int code;
size_t c;
for (c = 0; c < pr_immediate_strlen; )
{
@ -2009,7 +2011,7 @@ forcebyte:
}
c += len;
}
}
}*/
}
#endif
@ -3866,9 +3868,9 @@ void QCC_PR_ParsePrintDef (int type, QCC_def_t *def)
else if (def->isstatic)
modifiers = "static ";
if (flag_msvcstyle)
printf ("%s(%i) : %s%s %s is defined here\n", def->filen, def->s_line, modifiers, TypeName(def->type, tybuffer, sizeof(tybuffer)), def->name);
printf ("%s%s(%i) : %s%s%s %s%s%s is defined here\n", col_location, def->filen, def->s_line, col_none, modifiers, TypeName(def->type, tybuffer, sizeof(tybuffer)), col_symbol, def->name, col_none);
else
printf ("%s:%i: %s%s %s is defined here\n", def->filen, def->s_line, modifiers, TypeName(def->type, tybuffer, sizeof(tybuffer)), def->name);
printf ("%s%s:%i: %s%s%s %s%s%s is defined here\n", col_location, def->filen, def->s_line, col_none, modifiers, TypeName(def->type, tybuffer, sizeof(tybuffer)), col_symbol, def->name, col_none);
}
}
}
@ -3887,7 +3889,7 @@ static void QCC_PR_PrintMacro (qcc_includechunk_t *chunk)
if (chunk->cnst)
{
#if 1
printf ("%s:%i: %s is defined here\n", chunk->cnst->fromfile, chunk->cnst->fromline, chunk->cnst->name);
printf ("%s%s:%i: %s%s%s is defined here\n", col_location, chunk->cnst->fromfile, chunk->cnst->fromline, col_symbol, chunk->cnst->name, col_none);
#else
printf ("%s:%i: expanding %s\n", chunk->currentfilename, chunk->currentlinenumber, chunk->cnst->name);
#endif
@ -3904,7 +3906,7 @@ void QCC_PR_PrintScope (void)
if (pr_scope)
{
if (errorscope != pr_scope)
printf ("in function %s (line %i),\n", pr_scope->name, pr_scope->line);
printf ("in function %s%s%s (line %i),\n", col_symbol, pr_scope->name, col_none, pr_scope->line);
errorscope = pr_scope;
}
else
@ -3944,9 +3946,9 @@ void VARGS QCC_PR_ParseError (int errortype, const char *error, ...)
QCC_PR_PrintScope();
if (flag_msvcstyle)
printf ("%s(%i) : error: %s\n", s_filen, pr_source_line, string);
printf ("%s%s(%i) : %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string);
else
printf ("%s:%i: error: %s\n", s_filen, pr_source_line, string);
printf ("%s%s:%i: %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string);
longjmp (pr_parse_abort, 1);
}
@ -3965,9 +3967,9 @@ void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char
#endif
QCC_PR_PrintScope();
if (flag_msvcstyle)
printf ("%s(%i) : error: %s\n", s_filen, pr_source_line, string);
printf ("%s%s(%i) : %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string);
else
printf ("%s:%i: error: %s\n", s_filen, pr_source_line, string);
printf ("%s%s:%i: %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string);
QCC_PR_ParsePrintDef(WARN_ERROR, def);
@ -3988,9 +3990,9 @@ void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t def, const char
#endif
QCC_PR_PrintScope();
if (flag_msvcstyle)
printf ("%s(%i) : error: %s\n", s_filen, pr_source_line, string);
printf ("%s%s(%i) : %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string);
else
printf ("%s:%i: error: %s\n", s_filen, pr_source_line, string);
printf ("%s%s:%i: %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string);
QCC_PR_ParsePrintSRef(WARN_ERROR, def);
@ -4011,11 +4013,11 @@ pbool VARGS QCC_PR_PrintWarning (int type, const char *file, int line, const cha
if (!string)
;
else if (!file || !*file)
printf (":: error%s: %s\n", wnam, string);
printf (":: %serror%s%s: %s\n", col_error, wnam, col_none, string);
else if (flag_msvcstyle)
printf ("%s(%i) : error%s: %s\n", file, line, wnam, string);
printf ("%s%s(%i) : %serror%s%s: %s\n", col_location, file, line, col_error, wnam, col_none, string);
else
printf ("%s:%i: error%s: %s\n", file, line, wnam, string);
printf ("%s%s:%i: %serror%s%s: %s\n", col_location, file, line, col_error, wnam, col_none, string);
pr_error_count++;
}
else if (qccwarningaction[type] == 2)
@ -4023,11 +4025,11 @@ pbool VARGS QCC_PR_PrintWarning (int type, const char *file, int line, const cha
if (!string)
;
else if (!file || !*file)
printf (":: werror%s: %s\n", wnam, string);
printf (":: %swerror%s%s: %s\n", col_error, wnam, col_none, string);
else if (flag_msvcstyle)
printf ("%s(%i) : werror%s: %s\n", file, line, wnam, string);
printf ("%s%s(%i) : %swerror%s%s: %s\n", col_location, file, line, col_error, wnam, col_none, string);
else
printf ("%s:%i: werror%s: %s\n", file, line, wnam, string);
printf ("%s%s:%i: %swerror%s%s: %s\n", col_location, file, line, col_error, wnam, col_none, string);
pr_error_count++;
}
else
@ -4035,11 +4037,11 @@ pbool VARGS QCC_PR_PrintWarning (int type, const char *file, int line, const cha
if (!string)
;
else if (!file || !*file)
printf (":: warning%s: %s\n", wnam, string);
printf (":: %swarning%s%s: %s\n", col_warning, wnam, col_none, string);
else if (flag_msvcstyle)
printf ("%s(%i) : warning%s: %s\n", file, line, wnam, string);
printf ("%s%s(%i) : %swarning%s%s: %s\n", col_location, file, line, col_warning, wnam, col_none, string);
else
printf ("%s:%i: warning%s: %s\n", file, line, wnam, string);
printf ("%s%s:%i: %swarning%s%s: %s\n", col_location, file, line, col_warning, wnam, col_none, string);
pr_warning_count++;
}
return true;
@ -4112,7 +4114,7 @@ Gets the next token
void QCC_PR_Expect (const char *string)
{
if (STRCMP (string, pr_token))
QCC_PR_ParseError (ERR_EXPECTED, "expected %s, found %s",string, pr_token);
QCC_PR_ParseError (ERR_EXPECTED, "expected %s%s%s, found %s%s%s", col_location, string, col_none, col_name, pr_token, col_none);
QCC_PR_Lex ();
}
#endif
@ -4345,7 +4347,7 @@ char *QCC_PR_ParseName (void)
if (pr_token_type == tt_eof)
QCC_PR_ParseError (ERR_EOF, "unexpected EOF", pr_token);
else if (strcmp(pr_token, "...")) //seriously? someone used '...' as an intrinsic NAME?
QCC_PR_ParseError (ERR_NOTANAME, "\"%s\" - not a name", pr_token);
QCC_PR_ParseError (ERR_NOTANAME, "\"%s%s%s\" - not a name", col_name, pr_token, col_none);
}
if (strlen(pr_token) >= MAX_NAME-1)
QCC_PR_ParseError (ERR_NAMETOOLONG, "name too long");

View File

@ -387,7 +387,7 @@ compiler_flag_t compiler_flag[] = {
{&flag_allowuninit, hideflag, "allowuninit", "Uninitialised Locals", "Permit optimisations that may result in locals being uninitialised. This may allow for greater reductions in temps."},
{&flag_nopragmafileline,FLAG_MIDCOMPILE,"nofileline", "Ignore #pragma file", "Ignores #pragma file(foo) and #pragma line(foo), so that errors and symbols reflect the actual lines, instead of the original source."},
// {&flag_lno, hidedefaultflag,"lno", "Gen Debugging Info", "Writes debugging info."},
// {&flag_utf8, hidedefaultflag,"utf8", "Unicode", "Assume files to be UTF-8 encoded, instead of iso8859-1."},
{&flag_utf8strings, FLAG_MIDCOMPILE,"utf8", "Unicode", "String immediates will use utf-8 encoding, instead of quake's encoding."},
{&flag_embedsrc, FLAG_MIDCOMPILE,"embedsrc", "Embed Sources", "Write the sourcecode into the output file. The resulting .dat can be opened as a standard zip archive (or by fteqccgui).\nGood for GPL compliance!"},
// {&flag_noreflection, FLAG_MIDCOMPILE,"omitinternals","Omit Reflection Info", "Keeps internal symbols private (equivelent to unix's hidden visibility). This has the effect of reducing filesize, thwarting debuggers, and breaking saved games. This allows you to use arrays without massively bloating the size of your progs.\nWARNING: The bit about breaking saved games was NOT a joke, but does not apply to menuqc or csqc. It also interferes with FTE_MULTIPROGS."},
@ -1748,9 +1748,9 @@ pbool QCC_WriteData (int crc)
QCC_PR_Warning(wt, def->filen, def->s_line, NULL);
}
else if (def->arraysize)
QCC_PR_Warning(wt, def->filen, def->s_line, (dupewarncount++ >= 10 && !verbose)?NULL:"%s %s[%i] no references.", TypeName(def->type, typestr, sizeof(typestr)), def->name, def->arraysize);
QCC_PR_Warning(wt, def->filen, def->s_line, (dupewarncount++ >= 10 && !verbose)?NULL:"%s %s%s%s[%i] no references.", TypeName(def->type, typestr, sizeof(typestr)), col_symbol, def->name, col_none, def->arraysize);
else
QCC_PR_Warning(wt, def->filen, def->s_line, (dupewarncount++ >= 10 && !verbose)?NULL:"%s %s no references.", TypeName(def->type, typestr, sizeof(typestr)), def->name);
QCC_PR_Warning(wt, def->filen, def->s_line, (dupewarncount++ >= 10 && !verbose)?NULL:"%s %s%s%s no references.", TypeName(def->type, typestr, sizeof(typestr)), col_symbol, def->name, col_none);
}
pr_scope = NULL;
@ -1758,7 +1758,7 @@ pbool QCC_WriteData (int crc)
{
char typestr[256];
QCC_sref_t sr = {def, 0, def->type};
QCC_PR_Warning(WARN_NOTREFERENCED, def->filen, def->s_line, "%s %s = %s used, but not referenced.", TypeName(def->type, typestr, sizeof(typestr)), def->name, QCC_VarAtOffset(sr));
QCC_PR_Warning(WARN_NOTREFERENCED, def->filen, def->s_line, "%s %s%s%s = %s used, but not referenced.", TypeName(def->type, typestr, sizeof(typestr)), col_symbol, def->name, col_none, QCC_VarAtOffset(sr));
}
/*if (opt_unreferenced && def->type->type != ev_field)
{
@ -1959,7 +1959,7 @@ pbool QCC_WriteData (int crc)
}
if (dupewarncount > 10 && !verbose)
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "suppressed %i more warnings about precaches.", dupewarncount-10);
QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "suppressed %i more %swarnings%s about precaches.", dupewarncount-10, col_warning, col_none);
//PrintStrings ();
//PrintFunctions ();
@ -2462,7 +2462,7 @@ strofs = (strofs+3)&~3;
if (!SafeClose (h))
{
printf("Error while writing output %s\n", destfile);
printf("%sError%s while writing output %s\n", col_error, col_none, destfile);
return false;
}
@ -4268,8 +4268,6 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
opt_filenames = false;
}
}
else if (!stricmp(arg, "utf8"))
; //we always interpret input as utf-8, and thus output strings are 'utf-8' too. -fno-utf8 might be useful to asciify inputs, but that'll just break quake-encoded text, so why bother
else if (!stricmp(arg, "return-assignments"))
; //should really be a warning instead
else if (!stricmp(arg, "relaxed-switch"))
@ -4650,6 +4648,8 @@ void QCC_GenerateRelativePath(char *dest, size_t destsize, char *base, char *rel
}
}
const char *qcccol[COL_MAX];
int qcc_compileactive = false;
extern int accglobalsblock;
char *originalqccmsrc; //for autoprototype.
@ -4665,6 +4665,11 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine
char *s;
//make sure any print colours are set up properly.
for (p = 0; p < COL_MAX; p++)
if (!qcccol[p])
qcccol[p] = "";
s_filen = "cmdline";
s_filed = 0;
pr_source_line = 0;
@ -4706,7 +4711,7 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine
MAX_STRINGS = 1<<21;
MAX_GLOBALS = 1<<17;
MAX_FIELDS = 1<<13;
MAX_STATEMENTS = 0x100000;
MAX_STATEMENTS = 1<<21;
MAX_FUNCTIONS = 1<<15;
maxtypeinfos = 1<<16;
MAX_CONSTANTS = 1<<12;

View File

@ -3,6 +3,10 @@
#include <stdarg.h>
#include <stdio.h>
#if defined(__linux__) || defined(__unix__)
#include <unistd.h>
#endif
/*
==============
LoadFile
@ -126,6 +130,22 @@ int main (int argc, char **argv)
funcs.funcs.parms->WriteFile = QCC_WriteFile;
funcs.funcs.parms->Printf = logprintf;
funcs.funcs.parms->Sys_Error = Sys_Error;
#if defined(__linux__) || defined(__unix__)
if (isatty(STDOUT_FILENO))
{ //only use colours if its a tty, and not if we're redirected.
col_none = "\e[0;m"; //reset to white
col_error = "\e[0;31m"; //red
col_symbol = "\e[0;32m"; //green
col_warning = "\e[0;33m"; //yellow
//col_ = "\e[0;34m"; //blue
col_name = "\e[0;35m"; //magenta
//col_ = "\e[0;36m"; //cyan
col_location = "\e[0;1;37m"; //bright white
}
#endif
#ifdef _WIN32
logfile = fopen("fteqcc.log", "wt");
#endif