From 63ad5eff186bf1000b547237c24fc1522dbacd11 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 21 Jun 2014 04:10:15 -0700 Subject: [PATCH] Introduce basic methodmaps (PR #38). commit 1e5213d43fdd170bb0c30af914a4e40610014b2b Author: David Anderson Date: Sat Jun 21 04:09:27 2014 -0700 Quell MSVC C99 bugs. commit f2e166c5925fda49b5abeadc0aa0f9156b99cf11 Author: David Anderson Date: Sat Jun 21 03:59:23 2014 -0700 Fix varying levels of stupid memory errors. commit b0773d7be45345351ab1c1738681d5215a97f3f3 Author: David Anderson Date: Sat Jun 21 03:36:39 2014 -0700 Fix memory leak in parsing some control flow structures. commit 5aca55713cfc2dd09c5900132fc4a6be51e3e309 Author: David Anderson Date: Sat Jun 21 03:35:17 2014 -0700 Fix memory leak in struct parsing. commit b46ec5cd281b46177e83c4f0a4acac9cc1065c53 Author: David Anderson Date: Sat Jun 21 03:32:03 2014 -0700 Fix build. commit 17bbbb9a46bfc00862adca7d3e15369a48e9ac0f Merge: c083409 2107599 Author: David Anderson Date: Sat Jun 21 01:26:27 2014 -0700 Merge branch 'master' into methodmaps commit c083409b569abff13f24d3b8c47f8ff199036840 Author: David Anderson Date: Fri Jun 20 23:49:36 2014 -0700 Add VS2k13 support. commit b7993778494d538cb1c1965116030142a7f7765b Author: David Anderson Date: Fri Jun 20 01:28:08 2014 -0700 Implement destructors. commit 1a340dec260d079ed1b79351ed7b50b58a997cea Author: David Anderson Date: Fri Jun 20 00:08:04 2014 -0700 Add some tests. commit 12db52ee64eb009ead9294495e9034c63ab75b09 Author: David Anderson Date: Fri Jun 20 00:05:49 2014 -0700 Initial implementation of constructors. commit 074669a658caa2822aa864164b615a244c00a0bc Author: David Anderson Date: Thu Jun 19 22:42:35 2014 -0700 Add simple test harness. commit 27c1e3cf14e1e6c5cf35c80c792cce2744b804d7 Author: David Anderson Date: Thu Jun 19 22:15:42 2014 -0700 Big refactoring for new syntax. commit f3c37fdc919e76ee0815e2394cbe8d221f9fc0ca Author: David Anderson Date: Thu Jun 19 22:12:54 2014 -0700 Refactor tests for the new syntax. commit 6211f392f8e722b907474cf380cfac4347e46b8e Author: David Anderson Date: Wed Jun 18 22:25:48 2014 -0700 Make lexer tokens an enum. commit 5210b013756b0b00de3a61c6490685c768ff8cbd Author: David Anderson Date: Tue Jun 17 06:48:15 2014 -0700 Add comment. commit 06688ff4aced14077dd21a9cc1db4c26c7420ff3 Author: David Anderson Date: Tue Jun 17 06:46:10 2014 -0700 Allow |this| to be a base type of the methodmap. commit 05cf3682020e0e6d9f47b1a0a6727b9edbfe7622 Author: David Anderson Date: Mon Jun 16 22:11:58 2014 -0700 Unify duplicate typesymbol checking. commit 09161bf2691c8c1ed25b9b70fda01c336f21aa0b Author: David Anderson Date: Mon Jun 16 19:53:36 2014 -0700 Close loophole that allowed methodmaps for enums. commit 5bb4aeba89fec47a4de7a7532d27830999d1fcb4 Author: David Anderson Date: Mon Jun 16 01:50:42 2014 -0700 Add tests and dbi/handle changes. commit b9203e2491daec2a8073874d6375949483778d14 Author: David Anderson Date: Mon Jun 16 01:38:29 2014 -0700 Ensure methodmap tags are fixed. commit 878b80fd87a2ea500d3a28ce2d53f616d1efe5e8 Author: David Anderson Date: Mon Jun 16 01:36:04 2014 -0700 Implement inheritance. commit 6ba9e004fbae18ad68056368ddd0affdc78659f1 Author: David Anderson Date: Mon Jun 16 01:31:00 2014 -0700 Refactor matchtag() to not be insane. commit 4ede6343b0682c6df98fa869153828e92f891bcc Author: David Anderson Date: Mon Jun 16 01:20:50 2014 -0700 Fix indenting. commit e3ddef8916e3dd5f4ff0fe571d6e1c3acd163352 Author: David Anderson Date: Mon Jun 16 01:20:27 2014 -0700 Initial prototype. --- plugins/include/dbi.inc | 32 +- plugins/include/handles.inc | 16 +- plugins/testsuite/sqltest.sp | 18 +- sourcepawn/compiler/AMBuilder | 2 +- sourcepawn/compiler/sc.h | 237 +++--- sourcepawn/compiler/sc1.c | 518 +++++++++++- sourcepawn/compiler/sc2.c | 55 +- sourcepawn/compiler/sc3.c | 484 ++++++----- sourcepawn/compiler/sc5.c | 15 +- sourcepawn/compiler/sc5.scp | 768 ++++++++++-------- sourcepawn/compiler/sctracker.c | 162 +++- sourcepawn/compiler/sctracker.h | 54 ++ .../tests/fail-array-on-implicit-this.sp | 9 + .../tests/fail-array-on-implicit-this.txt | 1 + .../tests/fail-ctor-bad-return-type.sp | 13 + .../tests/fail-ctor-bad-return-type.txt | 1 + .../compiler/tests/fail-dtor-extra-args.sp | 8 + .../compiler/tests/fail-dtor-extra-args.txt | 1 + .../compiler/tests/fail-dtor-non-native.sp | 10 + .../compiler/tests/fail-dtor-non-native.txt | 1 + .../compiler/tests/fail-dtor-returns-value.sp | 8 + .../tests/fail-dtor-returns-value.txt | 1 + .../compiler/tests/fail-duplicate-methods.sp | 8 + .../compiler/tests/fail-duplicate-methods.txt | 1 + .../compiler/tests/fail-method-on-array.sp | 12 + .../compiler/tests/fail-method-on-array.txt | 1 + .../compiler/tests/fail-method-on-function.sp | 10 + .../tests/fail-method-on-function.txt | 1 + .../tests/fail-mismatch-on-implicit-this.sp | 9 + .../tests/fail-mismatch-on-implicit-this.txt | 1 + .../tests/fail-multi-tag-on-implicit-this.sp | 9 + .../tests/fail-multi-tag-on-implicit-this.txt | 1 + .../tests/fail-no-tag-on-implicit-this.sp | 9 + .../tests/fail-no-tag-on-implicit-this.txt | 1 + .../tests/fail-ref-on-implicit-this.sp | 9 + .../tests/fail-ref-on-implicit-this.txt | 1 + .../compiler/tests/ok-base-type-as-thistag.sp | 14 + sourcepawn/compiler/tests/ok-ctor-dtor.sp | 12 + sourcepawn/compiler/tests/ok-inheritance.sp | 14 + .../compiler/tests/ok-method-on-const.sp | 14 + .../compiler/tests/ok-method-on-constref.sp | 16 + .../compiler/tests/ok-method-on-element.sp | 11 + sourcepawn/compiler/tests/ok-method-on-ref.sp | 16 + .../compiler/tests/ok-method-on-scalar.sp | 13 + sourcepawn/compiler/tests/runtests.py | 74 ++ sourcepawn/compiler/tests/warn-bad-upcast.sp | 15 + sourcepawn/compiler/tests/warn-bad-upcast.txt | 1 + 47 files changed, 1956 insertions(+), 731 deletions(-) create mode 100644 sourcepawn/compiler/tests/fail-array-on-implicit-this.sp create mode 100644 sourcepawn/compiler/tests/fail-array-on-implicit-this.txt create mode 100644 sourcepawn/compiler/tests/fail-ctor-bad-return-type.sp create mode 100644 sourcepawn/compiler/tests/fail-ctor-bad-return-type.txt create mode 100644 sourcepawn/compiler/tests/fail-dtor-extra-args.sp create mode 100644 sourcepawn/compiler/tests/fail-dtor-extra-args.txt create mode 100644 sourcepawn/compiler/tests/fail-dtor-non-native.sp create mode 100644 sourcepawn/compiler/tests/fail-dtor-non-native.txt create mode 100644 sourcepawn/compiler/tests/fail-dtor-returns-value.sp create mode 100644 sourcepawn/compiler/tests/fail-dtor-returns-value.txt create mode 100644 sourcepawn/compiler/tests/fail-duplicate-methods.sp create mode 100644 sourcepawn/compiler/tests/fail-duplicate-methods.txt create mode 100644 sourcepawn/compiler/tests/fail-method-on-array.sp create mode 100644 sourcepawn/compiler/tests/fail-method-on-array.txt create mode 100644 sourcepawn/compiler/tests/fail-method-on-function.sp create mode 100644 sourcepawn/compiler/tests/fail-method-on-function.txt create mode 100644 sourcepawn/compiler/tests/fail-mismatch-on-implicit-this.sp create mode 100644 sourcepawn/compiler/tests/fail-mismatch-on-implicit-this.txt create mode 100644 sourcepawn/compiler/tests/fail-multi-tag-on-implicit-this.sp create mode 100644 sourcepawn/compiler/tests/fail-multi-tag-on-implicit-this.txt create mode 100644 sourcepawn/compiler/tests/fail-no-tag-on-implicit-this.sp create mode 100644 sourcepawn/compiler/tests/fail-no-tag-on-implicit-this.txt create mode 100644 sourcepawn/compiler/tests/fail-ref-on-implicit-this.sp create mode 100644 sourcepawn/compiler/tests/fail-ref-on-implicit-this.txt create mode 100644 sourcepawn/compiler/tests/ok-base-type-as-thistag.sp create mode 100644 sourcepawn/compiler/tests/ok-ctor-dtor.sp create mode 100644 sourcepawn/compiler/tests/ok-inheritance.sp create mode 100644 sourcepawn/compiler/tests/ok-method-on-const.sp create mode 100644 sourcepawn/compiler/tests/ok-method-on-constref.sp create mode 100644 sourcepawn/compiler/tests/ok-method-on-element.sp create mode 100644 sourcepawn/compiler/tests/ok-method-on-ref.sp create mode 100644 sourcepawn/compiler/tests/ok-method-on-scalar.sp create mode 100644 sourcepawn/compiler/tests/runtests.py create mode 100644 sourcepawn/compiler/tests/warn-bad-upcast.sp create mode 100644 sourcepawn/compiler/tests/warn-bad-upcast.txt diff --git a/plugins/include/dbi.inc b/plugins/include/dbi.inc index d1140bbf..8839eb2f 100644 --- a/plugins/include/dbi.inc +++ b/plugins/include/dbi.inc @@ -701,18 +701,7 @@ native SQL_TQuery(Handle:database, SQLTCallback:callback, const String:query[], * * @return A transaction handle. */ -native Handle:SQL_CreateTransaction(); - -/** - * Adds a query to a transaction object. - * - * @param txn A transaction handle. - * @param query Query string. - * @param data Extra data value to pass to the final callback. - * @return The index of the query in the transaction's query list. - * @error Invalid transaction handle. - */ -native SQL_AddQuery(Handle:txn, const String:query[], any:data=0); +native Transaction:SQL_CreateTransaction(); /** * Callback for a successful transaction. @@ -739,6 +728,23 @@ functag public SQLTxnSuccess(Handle:db, any:data, numQueries, Handle:results[], */ functag public SQLTxnFailure(Handle:db, any:data, numQueries, const String:error[], failIndex, any:queryData[]); +/** + * Adds a query to a transaction object. + * + * @param txn A transaction handle. + * @param query Query string. + * @param data Extra data value to pass to the final callback. + * @return The index of the query in the transaction's query list. + * @error Invalid transaction handle. + */ +native SQL_AddQuery(Transaction:txn, const String:query[], any:data=0); + +methodmap Transaction < Handle +{ + public Transaction() = SQL_CreateTransaction; + public AddQuery() = SQL_AddQuery; +}; + /** * Sends a transaction to the database thread. The transaction handle is * automatically closed. When the transaction completes, the optional @@ -755,7 +761,7 @@ functag public SQLTxnFailure(Handle:db, any:data, numQueries, const String:error */ native SQL_ExecuteTransaction( Handle:db, - Handle:txn, + Transaction:txn, SQLTxnSuccess:onSuccess=SQLTxnSuccess:-1, SQLTxnFailure:onError=SQLTxnFailure:-1, any:data=0, diff --git a/plugins/include/handles.inc b/plugins/include/handles.inc index b09703d0..d811908d 100644 --- a/plugins/include/handles.inc +++ b/plugins/include/handles.inc @@ -36,9 +36,9 @@ #define _handles_included /** - * Handle helper macros. + * Preset Handle values. */ -enum Handle +enum Handle: // Tag disables introducing "Handle" as a symbol. { INVALID_HANDLE = 0, }; @@ -52,10 +52,9 @@ enum Handle * sure you read the documentation on whatever provided the Handle. * * @param hndl Handle to close. - * @return True if successful, false if not closeable. * @error Invalid handles will cause a run time error. */ -native bool:CloseHandle(Handle:hndl); +native CloseHandle(Handle:hndl); /** * Clones a Handle. When passing handles in between plugins, caching handles @@ -76,6 +75,15 @@ native bool:CloseHandle(Handle:hndl); */ native Handle:CloneHandle(Handle:hndl, Handle:plugin=INVALID_HANDLE); +/** + * Helper for object-oriented syntax. + */ +methodmap Handle +{ + public Clone() = CloneHandle; + public ~Handle() = CloseHandle; +}; + /** * Do not use this function. Returns if a Handle and its contents * are readable, whereas INVALID_HANDLE only checks for the absence diff --git a/plugins/testsuite/sqltest.sp b/plugins/testsuite/sqltest.sp index e615713f..1f5ac978 100644 --- a/plugins/testsuite/sqltest.sp +++ b/plugins/testsuite/sqltest.sp @@ -279,10 +279,10 @@ public Action:Command_TestTxn(args) SetTestContext("CreateTransaction"); - new Handle:txn = SQL_CreateTransaction(); - AssertEq("AddQuery", SQL_AddQuery(txn, "INSERT INTO egg (id) VALUES (4)", 50), 0); - AssertEq("AddQuery", SQL_AddQuery(txn, "INSERT INTO egg (id) VALUES (5)", 60), 1); - AssertEq("AddQuery", SQL_AddQuery(txn, "SELECT COUNT(id) FROM egg", 70), 2); + new Transaction:txn = SQL_CreateTransaction(); + AssertEq("AddQuery", txn.AddQuery("INSERT INTO egg (id) VALUES (4)", 50), 0); + AssertEq("AddQuery", txn.AddQuery("INSERT INTO egg (id) VALUES (5)", 60), 1); + AssertEq("AddQuery", txn.AddQuery("SELECT COUNT(id) FROM egg", 70), 2); SQL_ExecuteTransaction( db, txn, @@ -292,9 +292,9 @@ public Action:Command_TestTxn(args) ); txn = SQL_CreateTransaction(); - AssertEq("AddQuery", SQL_AddQuery(txn, "INSERT INTO egg (id) VALUES (6)", 50), 0); - AssertEq("AddQuery", SQL_AddQuery(txn, "INSERT INTO egg (id) VALUES (6)", 60), 1); - AssertEq("AddQuery", SQL_AddQuery(txn, "SELECT COUNT(id) FROM egg", 70), 2); + AssertEq("AddQuery", txn.AddQuery("INSERT INTO egg (id) VALUES (6)", 50), 0); + AssertEq("AddQuery", txn.AddQuery("INSERT INTO egg (id) VALUES (6)", 60), 1); + AssertEq("AddQuery", txn.AddQuery("SELECT COUNT(id) FROM egg", 70), 2); SQL_ExecuteTransaction( db, txn, @@ -306,13 +306,13 @@ public Action:Command_TestTxn(args) // Make sure the transaction was rolled back - COUNT should be 5. txn = SQL_CreateTransaction(); AssertEq("CloneHandle", _:CloneHandle(txn), _:INVALID_HANDLE); - SQL_AddQuery(txn, "SELECT COUNT(id) FROM egg"); + txn.AddQuery("SELECT COUNT(id) FROM egg"); SQL_ExecuteTransaction( db, txn, Txn_Test3_OnSuccess ); - CloseHandle(db); + db.Close(); return Plugin_Handled; } diff --git a/sourcepawn/compiler/AMBuilder b/sourcepawn/compiler/AMBuilder index aae178bc..48991705 100644 --- a/sourcepawn/compiler/AMBuilder +++ b/sourcepawn/compiler/AMBuilder @@ -11,7 +11,7 @@ compiler.includes += [ ] if compiler.cc.behavior == 'gcc': - compiler.cflags += ['-Wno-format'] + compiler.cflags += ['-std=c99', '-Wno-format'] if builder.target_platform == 'linux': compiler.postlink += ['-lgcc', '-lm'] elif compiler.cc.behavior == 'msvc': diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 0b87fe0e..a226aa0d 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -113,7 +113,8 @@ typedef struct s_constvalue { */ typedef struct s_symbol { struct s_symbol *next; - struct s_symbol *parent; /* hierarchical types (multi-dimensional arrays) */ + struct s_symbol *parent; /* hierarchical types */ + struct s_symbol *target; /* proxy target */ char name[sNAMEMAX+1]; uint32_t hash; /* value derived from name, for quicker searching */ cell addr; /* address or offset (or value for constant, index for native function) */ @@ -150,7 +151,6 @@ typedef struct s_symbol { char *documentation; /* optional documentation string */ } symbol; - /* Possible entries for "ident". These are used in the "symbol", "value" * and arginfo structures. Not every constant is valid for every use. * In an argument list, the list is terminated with a "zero" ident; labels @@ -168,6 +168,7 @@ typedef struct s_symbol { #define iFUNCTN 9 #define iREFFUNC 10 #define iVARARGS 11 /* function specified ... as argument(s) */ +#define iPROXY 12 /* proxies to another symbol. */ /* Possible entries for "usage" * @@ -237,7 +238,7 @@ typedef struct s_symbol { #define sSTATEVAR 3 /* criterion to find variables (sSTATEVAR implies a global variable) */ -typedef struct s_value { +typedef struct value_s { symbol *sym; /* symbol in symbol table, NULL for (constant) expression */ cell constval; /* value of the constant expression (if ident==iCONSTEXPR) * also used for the size of a literal array */ @@ -249,6 +250,20 @@ typedef struct s_value { cell *arrayidx; /* last used array indices, for checking self assignment */ } value; +/* Wrapper around value + l/rvalue bit. */ +typedef struct svalue_s { + value val; + int lvalue; +} svalue; + +/* For parsing declarations. */ +typedef struct { + char type[sNAMEMAX + 1]; + constvalue *enumroot; + int tag; + char usage; +} declinfo_t; + /* "while" statement queue (also used for "for" and "do - while" loops) */ enum { wqBRK, /* used to restore stack for "break" */ @@ -284,6 +299,13 @@ typedef struct s_stringpair { char *documentation; } stringpair; +// Helper for token info. +typedef struct { + int id; + cell val; + char *str; +} token_t; + /* macros for code generation */ #define opcodes(n) ((n)*sizeof(cell)) /* opcode size */ #define opargs(n) ((n)*sizeof(cell)) /* size of typical argument */ @@ -291,101 +313,110 @@ typedef struct s_stringpair { /* Tokens recognized by lex() * Some of these constants are assigned as well to the variable "lastst" (see SC1.C) */ -#define tFIRST 256 /* value of first multi-character operator */ -#define tMIDDLE 280 /* value of last multi-character operator */ -#define tLAST 332 /* value of last multi-character match-able token */ -/* multi-character operators */ -#define taMULT 256 /* *= */ -#define taDIV 257 /* /= */ -#define taMOD 258 /* %= */ -#define taADD 259 /* += */ -#define taSUB 260 /* -= */ -#define taSHL 261 /* <<= */ -#define taSHRU 262 /* >>>= */ -#define taSHR 263 /* >>= */ -#define taAND 264 /* &= */ -#define taXOR 265 /* ^= */ -#define taOR 266 /* |= */ -#define tlOR 267 /* || */ -#define tlAND 268 /* && */ -#define tlEQ 269 /* == */ -#define tlNE 270 /* != */ -#define tlLE 271 /* <= */ -#define tlGE 272 /* >= */ -#define tSHL 273 /* << */ -#define tSHRU 274 /* >>> */ -#define tSHR 275 /* >> */ -#define tINC 276 /* ++ */ -#define tDEC 277 /* -- */ -#define tELLIPS 278 /* ... */ -#define tDBLDOT 279 /* .. */ -#define tDBLCOLON 280 /* :: */ +enum { + /* value of first multi-character operator */ + tFIRST = 256, + /* multi-character operators */ + taMULT = tFIRST, /* *= */ + taDIV, /* /= */ + taMOD, /* %= */ + taADD, /* += */ + taSUB, /* -= */ + taSHL, /* <<= */ + taSHRU, /* >>>= */ + taSHR, /* >>= */ + taAND, /* &= */ + taXOR, /* ^= */ + taOR, /* |= */ + tlOR, /* || */ + tlAND, /* && */ + tlEQ, /* == */ + tlNE, /* != */ + tlLE, /* <= */ + tlGE, /* >= */ + tSHL, /* << */ + tSHRU, /* >>> */ + tSHR, /* >> */ + tINC, /* ++ */ + tDEC, /* -- */ + tELLIPS, /* ... */ + tDBLDOT, /* .. */ + tDBLCOLON, /* :: */ + /* value of last multi-character operator */ + tMIDDLE = tDBLCOLON, /* reserved words (statements) */ -#define tASSERT 281 -#define tBEGIN 282 -#define tBREAK 283 -#define tCASE 284 -#define tCELLSOF 285 -#define tCHAR 286 -#define tCONST 287 -#define tCONTINUE 288 -#define tDEFAULT 289 -#define tDEFINED 290 -#define tDO 291 -#define tELSE 292 -#define tEND 293 -#define tENUM 294 -#define tEXIT 295 -#define tFOR 296 -#define tFORWARD 297 -#define tFUNCENUM 298 -#define tFUNCTAG 299 -#define tGOTO 300 -#define tIF 301 -#define tNATIVE 302 -#define tNEW 303 -#define tDECL 304 -#define tOPERATOR 305 -#define tPUBLIC 306 -#define tRETURN 307 -#define tSIZEOF 308 -#define tSLEEP 309 -#define tSTATIC 310 -#define tSTOCK 311 -#define tSTRUCT 312 -#define tSWITCH 313 -#define tTAGOF 314 -#define tTHEN 315 -#define tWHILE 316 -/* compiler directives */ -#define tpASSERT 317 /* #assert */ -#define tpDEFINE 318 -#define tpELSE 319 /* #else */ -#define tpELSEIF 320 /* #elseif */ -#define tpEMIT 321 -#define tpENDIF 322 -#define tpENDINPUT 323 -#define tpENDSCRPT 324 -#define tpERROR 325 -#define tpFILE 326 -#define tpIF 327 /* #if */ -#define tINCLUDE 328 -#define tpLINE 329 -#define tpPRAGMA 330 -#define tpTRYINCLUDE 331 -#define tpUNDEF 332 -/* semicolon is a special case, because it can be optional */ -#define tTERM 333 /* semicolon or newline */ -#define tENDEXPR 334 /* forced end of expression */ -/* other recognized tokens */ -#define tNUMBER 335 /* integer number */ -#define tRATIONAL 336 /* rational number */ -#define tSYMBOL 337 -#define tLABEL 338 -#define tSTRING 339 -#define tEXPR 341 /* for assigment to "lastst" only (see SC1.C) */ -#define tENDLESS 342 /* endless loop, for assigment to "lastst" only */ -#define tEMPTYBLOCK 343 /* empty blocks for AM bug 4825 */ + tASSERT, + tBEGIN, + tBREAK, + tCASE, + tCELLSOF, + tCHAR, + tCONST, + tCONTINUE, + tDEFAULT, + tDEFINED, + tDELETE, + tDO, + tELSE, + tEND, + tENUM, + tEXIT, + tFOR, + tFORWARD, + tFUNCENUM, + tFUNCTAG, + tGOTO, + tIF, + tINT, + tMETHODMAP, + tNATIVE, + tNEW, + tDECL, + tOPERATOR, + tPUBLIC, + tRETURN, + tSIZEOF, + tSLEEP, + tSTATIC, + tSTOCK, + tSTRUCT, + tSWITCH, + tTAGOF, + tTHEN, + tVOID, + tWHILE, + /* compiler directives */ + tpASSERT, /* #assert */ + tpDEFINE, + tpELSE, /* #else */ + tpELSEIF, /* #elseif */ + tpEMIT, + tpENDIF, + tpENDINPUT, + tpENDSCRPT, + tpERROR, + tpFILE, + tpIF, /* #if */ + tINCLUDE, + tpLINE, + tpPRAGMA, + tpTRYINCLUDE, + tpUNDEF, + tLAST = tpUNDEF, /* value of last multi-character match-able token */ + /* semicolon is a special case, because it can be optional */ + tTERM, /* semicolon or newline */ + tENDEXPR, /* forced end of expression */ + /* other recognized tokens */ + tNUMBER, /* integer number */ + tRATIONAL, /* rational number */ + tSYMBOL, + tLABEL, + tSTRING, + tEXPR, /* for assigment to "lastst" only (see SC1.C) */ + tENDLESS, /* endless loop, for assigment to "lastst" only */ + tEMPTYBLOCK, /* empty blocks for AM bug 4825 */ + tLAST_TOKEN_ID +}; /* (reversed) evaluation of staging buffer */ #define sSTARTREORDER 0x01 @@ -467,8 +498,12 @@ typedef enum s_optmark { int pc_compile(int argc, char **argv); int pc_addconstant(char *name,cell value,int tag); int pc_addtag(char *name); +int pc_addtag_flags(char *name, int flags); +int pc_findtag(const char *name); int pc_addfunctag(char *name); int pc_enablewarning(int number,int enable); +const char *pc_tagname(int tag); +int parse_decl(declinfo_t *decl, const token_t *first, int flags); /* * Functions called from the compiler (to be implemented by you) @@ -553,11 +588,13 @@ SC_FUNC int plungefile(char *name,int try_currentpath,int try_includepaths); / SC_FUNC void preprocess(void); SC_FUNC void lexinit(void); SC_FUNC int lex(cell *lexvalue,char **lexsym); +SC_FUNC int lextok(token_t *tok); SC_FUNC void lexpush(void); SC_FUNC void lexclr(int clreol); SC_FUNC int matchtoken(int token); SC_FUNC int tokeninfo(cell *val,char **str); SC_FUNC int needtoken(int token); +SC_FUNC int expecttoken(int id, token_t *tok); SC_FUNC void litadd(cell value); SC_FUNC void litinsert(cell value,int pos); SC_FUNC int alphanum(char c); @@ -570,8 +607,7 @@ SC_FUNC symbol *findglb(const char *name,int filter); SC_FUNC symbol *findloc(const char *name); SC_FUNC symbol *findconst(const char *name,int *matchtag); SC_FUNC symbol *finddepend(const symbol *parent); -SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag, - int usage); +SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag, int usage); SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag, int dim[],int numdim,int idxtag[]); SC_FUNC symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int tag, @@ -834,7 +870,8 @@ SC_VDECL int sc_curstates; /* ID of the current state list */ SC_VDECL int pc_optimize; /* (peephole) optimization level */ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */ SC_VDECL int pc_functag; /* global function tag */ -SC_VDECL int pc_tag_string; /* global string tag */ +SC_VDECL int pc_tag_string; /* global String tag */ +SC_VDECL int pc_tag_void; /* global void tag */ SC_VDECL int pc_anytag; /* global any tag */ SC_VDECL int glbstringread; /* last global string read */ diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 28c3215b..abe822c2 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1,3 +1,4 @@ +/* vim: set sts=2 ts=8 sw=2 tw=99 et: */ /* Pawn compiler * * Function and variable definition and declaration, statement parser. @@ -75,6 +76,7 @@ int pc_anytag = 0; int pc_functag = 0; int pc_tag_string = 0; +int pc_tag_void = 0; static void resetglobals(void); static void initglobals(void); @@ -93,6 +95,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic, int stock,int fconst); static void declstructvar(char *firstname,int fpublic, pstruct_t *pstruct); static int declloc(int fstatic); +static void dodelete(); static void decl_const(int table); static void declstruct(); static void decl_enum(int table); @@ -107,7 +110,7 @@ static cell initvector(int ident,int tag,cell size,int fillzero, static cell init(int ident,int *tag,int *errorfound); static int getstates(const char *funcname); static void attachstatelist(symbol *sym, int state_id); -static void funcstub(int fnative); +static symbol *funcstub(int fnative); static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stock); static int declargs(symbol *sym,int chkshadow); static void doarg(char *name,int ident,int offset,int tags[],int numtags, @@ -137,6 +140,7 @@ static void dogoto(void); static void dolabel(void); static void doreturn(void); static void dofuncenum(int listmode); +static void domethodmap(LayoutSpec spec); static void dobreak(void); static void docont(void); static void dosleep(void); @@ -345,7 +349,8 @@ int pc_compile(int argc, char *argv[]) #endif resetglobals(); pstructs_free(); - funcenums_free(); + funcenums_free(); + methodmaps_free(); sc_ctrlchar=sc_ctrlchar_org; sc_packstr=lcl_packstr; sc_needsemicolon=lcl_needsemicolon; @@ -407,6 +412,7 @@ int pc_compile(int argc, char *argv[]) reduce_referrers(&glbtab); delete_symbols(&glbtab,0,TRUE,FALSE); funcenums_free(); + methodmaps_free(); pstructs_free(); #if !defined NO_DEFINE delete_substtable(); @@ -529,6 +535,7 @@ cleanup: delete_sourcefiletable(); delete_dbgstringtable(); funcenums_free(); + methodmaps_free(); pstructs_free(); #if !defined NO_DEFINE delete_substtable(); @@ -628,14 +635,33 @@ static void inst_datetime_defines(void) insert_subst("__TIME__", ltime, 8); } +const char *pc_tagname(int tag) +{ + constvalue *ptr=tagname_tab.next; + for (; ptr; ptr=ptr->next) { + if ((int)(ptr->value & TAGMASK) == (tag & TAGMASK)) + return ptr->name; + } + return ""; +} + +int pc_findtag(const char *name) +{ + constvalue *ptr=tagname_tab.next; + for (; ptr; ptr=ptr->next) { + if (strcmp(name,ptr->name)==0) + return (int)(ptr->value & TAGMASK); + } + return -1; +} + #if defined __cplusplus extern "C" #endif int pc_addtag(char *name) { - cell val; - constvalue *ptr; - int last,tag; + int val; + int flags = 0; if (name==NULL) { /* no tagname was given, check for one */ @@ -645,6 +671,17 @@ int pc_addtag(char *name) } /* if */ } /* if */ + if (isupper(*name)) + flags |= FIXEDTAG; + + return pc_addtag_flags(name, flags); +} + +int pc_addtag_flags(char *name, int flags) +{ + constvalue *ptr; + int last,tag; + assert(strchr(name,':')==NULL); /* colon should already have been stripped */ last=0; ptr=tagname_tab.next; @@ -661,8 +698,7 @@ int pc_addtag(char *name) /* tagname currently unknown, add it */ tag=last+1; /* guaranteed not to exist already */ - if (isupper(*name)) - tag |= (int)FIXEDTAG; + tag|=flags; append_constval(&tagname_tab,name,(cell)tag,0); return tag; } @@ -1326,6 +1362,8 @@ static void setconstants(void) pc_anytag = pc_addtag("any"); pc_functag = pc_addfunctag("Function"); pc_tag_string = pc_addtag("String"); + pc_tag_void = pc_addtag_flags("void", FIXEDTAG); + sc_rationaltag = pc_addtag("Float"); add_constant("true",1,sGLOBAL,1); /* boolean flags */ add_constant("false",0,sGLOBAL,1); @@ -1488,6 +1526,9 @@ static void parse(void) case tFUNCENUM: dofuncenum(TRUE); break; + case tMETHODMAP: + domethodmap(Layout_MethodMap); + break; case tFUNCTAG: dofuncenum(FALSE); break; @@ -1826,6 +1867,8 @@ static void declstructvar(char *firstname,int fpublic, pstruct_t *pstruct) matchtoken(';'); /* Mark it as undefined instead */ mysym->usage = uSTOCK|uSTRUCT; + free(found); + free(values); return; } else { mysym->usage = usage; @@ -3110,6 +3153,13 @@ static void decl_const(int vclass) needtoken(tTERM); } +static void check_struct_name(const char *name) +{ + LayoutSpec spec = deduce_layout_spec_by_name(name); + if (!can_redef_layout_spec(spec, Layout_PawnStruct)) + error(110, name, layout_spec_name(spec)); +} + /* * declstruct - declare a struct type */ @@ -3128,10 +3178,7 @@ static void declstruct(void) error(93); } - if (pstructs_find(str) != NULL) - { - error(98); - } + check_struct_name(str); pstruct = pstructs_add(str); @@ -3202,13 +3249,423 @@ static void declstruct(void) } if (pstructs_addarg(pstruct, &arg) == NULL) { - error(99, arg.name, pstruct->name); + error(103, arg.name, layout_spec_name(Layout_PawnStruct)); } } while (matchtoken(',')); needtoken('}'); matchtoken(';'); /* eat up optional semicolon */ } +int parse_typeexpr(declinfo_t *decl, const token_t *first, int flags) +{ + token_t tok; + + if (first) { + tok = *first; + } else { + lextok(&tok); + } + + if (tok.id == tCONST) { + decl->usage |= uCONST; + lextok(&tok); + } + + if (tok.id == tLABEL || tok.id == '[') + return FALSE; + + switch (tok.id) { + case tINT: + strcpy(decl->type, "int"); + decl->tag = 0; + break; + case tCHAR: + strcpy(decl->type, "char"); + decl->tag = pc_tag_string; + break; + case tVOID: + strcpy(decl->type, "void"); + decl->tag = pc_tag_void; + break; + case tSYMBOL: + strcpy(decl->type, tok.str); + if (strcmp(decl->type, "float") == 0) { + decl->tag = sc_rationaltag; + } else { + decl->tag = pc_findtag(decl->type); + if (decl->tag == sc_rationaltag) + error(98, "Float", "float"); + else if (decl->tag == pc_tag_string) + error(98, "String", "char"); + else if (decl->tag == 0) + error(98, "_", "int"); + } + default: + return FALSE; + } + + return TRUE; +} + +// Parse a new-style declaration. If the name was already fetched (because we +// didn't have enough lookahead), it can be given ahead of time. +int parse_decl(declinfo_t *decl, const token_t *first, int flags) +{ + memset(decl, 0, sizeof(*decl)); + + if (!parse_typeexpr(decl, first, flags)) + return FALSE; + + return TRUE; +} + +void define_constructor(methodmap_t *map, methodmap_method_t *method) +{ + symbol *sym = findglb(map->name, sGLOBAL); + if (sym && sym->ident == iPROXY && sym->parent == method->target) + return; + + if (sym) { + const char *type = ""; + switch (sym->ident) { + case iVARIABLE: + case iARRAY: + case iARRAYCELL: + case iARRAYCHAR: + type = "variable"; + break; + case iFUNCTN: + type = "function"; + break; + } + error(113, map->name, type); + return; + } + + sym = addsym(map->name, 0, iPROXY, sGLOBAL, 0, 0); + sym->target = method->target; +} + +methodmap_method_t *parse_method(methodmap_t *map) +{ + int is_dtor = 0; + int is_bind = 0; + int is_native = 0; + const char *spectype = layout_spec_name(map->spec); + + // We keep a wider buffer since we do name munging. + char ident[sNAMEMAX * 3 + 1] = ""; + char bindname[sNAMEMAX * 3 + 1] = ""; + + needtoken(tPUBLIC); + + token_t tok; + declinfo_t decl; + if (matchtoken('~')) { + // We got something like "public ~Blah = X" + is_bind = 1; + is_dtor = 1; + if (needtoken(tSYMBOL)) { + tokeninfo(&tok.val, &tok.str); + strcpy(ident, tok.str); + } + needtoken('('); + needtoken(')'); + needtoken('='); + if (!expecttoken(tSYMBOL, &tok)) + return NULL; + strcpy(bindname, tok.str); + } else { + is_native = matchtoken(tNATIVE); + + if (is_native) { + // If we have a native, we should always get a type expression next. + parse_decl(&decl, NULL, 0); + } else { + // Parsing "public Clone =" and "public Handle Clone = " requires two tokens + // of lookahead. By the time we see the '=' in the first example, we'd have + // expected a function name, but it's too late to back up - _lexpush is only + // one token deep. + // + // If we see a symbol and a '=', we know it's a simple binding. Otherwise, + // we have to take the token we got from lextok() and ask parse_decl() to + // start parsing it as a type expression. + int is_symbol = (lextok(&tok) == tSYMBOL); + if (is_symbol) { + // Save the string because matchtoken() will overwrite the token buffer. + // Note we also have to repoint tok so parse_decl will point at our + // local copy. + strcpy(ident, tok.str); + tok.str = ident; + + if (matchtoken('(')) { + needtoken(')'); + needtoken('='); + + // Grab the name we're binding to. + is_bind = 1; + if (!expecttoken(tSYMBOL, &tok)) + return NULL; + strcpy(bindname, tok.str); + } + } + + if (!is_bind) { + // We didn't find an '=', so proceed with a normal function signature. + parse_decl(&decl, &tok, 0); + is_dtor = matchtoken('~'); + + if (lextok(&tok) != tSYMBOL) { + // Error, and if EOF, return. The lexpush is so we don't accidentally + // skip over a terminator or something, since we scan to the end of the + // line. + lexpush(); + error(111); + if (tok.id == 0) + return NULL; + } + + strcpy(ident, tok.str); + } // if (tok == symbol && matchtoken('=')) + } // if (is_native) + } // if (matchtoken('~')) + + symbol *target = NULL; + if (is_bind) { + target = findglb(bindname, sGLOBAL); + if (!target) + error(17, ident); + else if (target->ident != iFUNCTN) + error(10); + } else { + error(10); + } + + if (!target) + return NULL; + + if (is_dtor) { + // Make sure the dtor has the right name. + if (strcmp(ident, map->name) != 0) + error(114, spectype, map->name); + + if (!(target->usage & uNATIVE)) { + // Must be a native. + error(118); + return NULL; + } + + if (target->tag != 0 && target->tag != pc_tag_void) { + // Cannot return a value. + error(99); + return NULL; + } + + if (target->dim.arglist[0].ident && target->dim.arglist[1].ident) { + // Cannot have extra arguments. + error(119); + return NULL; + } + + // Make sure the final name includes the ~. + strcpy(ident, "~"); + strcat(ident, map->name); + } + + // Check that a method with this name doesn't already exist. + for (size_t i = 0; i < map->nummethods; i++) { + if (strcmp(map->methods[i]->name, ident) == 0) { + error(103, ident, spectype); + return NULL; + } + } + + methodmap_method_t *method = (methodmap_method_t *)calloc(1, sizeof(methodmap_method_t)); + strcpy(method->name, ident); + method->target = target; + if (is_dtor) + map->dtor = method; + + // If the symbol is a constructor, we bypass the initial argument checks, + // and instead require that it returns something with the same tag. + if (strcmp(ident, map->name) == 0) { + if (target->tag != map->tag) + error(112, map->name); + define_constructor(map, method); + return method; + } + + // Check the implicit this parameter. Currently we only allow scalars. As + // to not encourage enum-structs, we will not allow those either. + const arginfo *first_arg = &target->dim.arglist[0]; + if (first_arg->ident == 0 || + first_arg->ident != iVARIABLE || + (first_arg->usage & uCONST) || + first_arg->hasdefault || + first_arg->numtags != 1) + { + free(method); + error(108, spectype, map->name); + return NULL; + } + + // Ensure the methodmap tag is compatible with |this|. + int ok = 0; + for (methodmap_t *mapptr = map; mapptr; mapptr = mapptr->parent) { + if (first_arg->tags[0] == mapptr->tag) { + ok = 1; + break; + } + } + if (!ok) + error(108, spectype, map->name); + + return method; +} + +static int consume_line() +{ + int val; + char *str; + + // First check for EOF. + if (lex(&val, &str) == 0) + return FALSE; + lexpush(); + + while (!matchtoken(tTERM)) { + // Check for EOF. + if (lex(&val, &str) == 0) + return FALSE; + } + + return TRUE; +} + +/** + * domethodmap - declare a method map for OO-ish syntax. + * + */ +static void domethodmap(LayoutSpec spec) +{ + int val; + char *str; + LayoutSpec old_spec; + methodmap_t *parent = NULL; + const char *spectype = layout_spec_name(spec); + + // methodmap ::= "methodmap" symbol ("<" symbol)? "{" methodmap-body "}" + char mapname[sNAMEMAX + 1]; + if (lex(&val, &str) != tSYMBOL) + error(93); + strcpy(mapname, str); + + if (!isupper(*mapname)) + error(109, spectype); + + old_spec = deduce_layout_spec_by_name(mapname); + if (!can_redef_layout_spec(spec, old_spec)) + error(110, mapname, layout_spec_name(old_spec)); + + if (matchtoken('<')) { + if (lex(&val, &str) != tSYMBOL) { + error(93); + return; + } + + if ((parent = methodmap_find_by_name(str)) == NULL) { + error(102, str); + } + } + + methodmap_t *map = (methodmap_t *)calloc(1, sizeof(methodmap_t)); + map->parent = parent; + map->tag = pc_addtag(mapname); + map->spec = spec; + strcpy(map->name, mapname); + + methodmap_add(map); + + needtoken('{'); + while (!matchtoken('}')) { + methodmap_method_t *method; + methodmap_method_t **methods; + + if ((method = parse_method(map)) == NULL) { + if (!consume_line()) + return; + continue; + } + + needtoken(tTERM); + + methods = (methodmap_method_t **)realloc(map->methods, sizeof(methodmap_method_t *) * (map->nummethods + 1)); + if (!methods) { + error(123); + return; + } + map->methods = methods; + map->methods[map->nummethods++] = method; + } + + needtoken(tTERM); +} + +// delete ::= "delete" expr +static void dodelete() +{ + int tag; + symbol *sym; + + int ident = doexpr(TRUE, FALSE, TRUE, FALSE, &tag, &sym, TRUE); + needtoken(tTERM); + + switch (ident) { + case iFUNCTN: + case iREFFUNC: + error(115, "functions"); + return; + + case iARRAY: + case iREFARRAY: + case iARRAYCELL: + case iARRAYCHAR: + error(115, "arrays"); + return; + } + + if (tag == 0) { + error(115, "primitive types or enums"); + return; + } + + methodmap_t *map = methodmap_find_by_tag(tag); + if (!map) { + error(115, pc_tagname(tag)); + return; + } + + if (!map->dtor) { + error(115, layout_spec_name(map->spec), map->name); + return; + } + + // For some reason, we don't get a sysreq.n once this passes through the + // peephole optimizer. I can't tell why. -dvander + // + // push pri + // push.c 1 + // sysreq.c N 1 + // stack 8 + pushreg(sPRI); + markexpr(sPARM,NULL,0); + { + pushval(1); + ffcall(map->dtor->target, NULL, 1); + map->dtor->target->usage |= uREAD; + } + markexpr(sEXPR,NULL,0); +} /** * dofuncenum - declare function enumerations @@ -3449,13 +3906,17 @@ static void decl_enum(int vclass) cell increment,multiplier; constvalue *enumroot; symbol *enumsym; + LayoutSpec spec; /* get an explicit tag, if any (we need to remember whether an explicit * tag was passed, even if that explicit tag was "_:", so we cannot call * pc_addtag() here */ if (lex(&val,&str)==tLABEL) { - tag=pc_addtag(str); + tag = pc_addtag(str); + spec = deduce_layout_spec_by_tag(tag); + if (!can_redef_layout_spec(spec, Layout_Enum)) + error(110, str, layout_spec_name(spec)); explicittag=TRUE; } else { lexpush(); @@ -3466,8 +3927,16 @@ static void decl_enum(int vclass) /* get optional enum name (also serves as a tag if no explicit tag was set) */ if (lex(&val,&str)==tSYMBOL) { /* read in (new) token */ strcpy(enumname,str); /* save enum name (last constant) */ - if (!explicittag) + if (!explicittag) { tag=pc_addtag(enumname); + spec = deduce_layout_spec_by_tag(tag); + if (!can_redef_layout_spec(spec, Layout_Enum)) + error(110, enumname, layout_spec_name(spec)); + } else { + spec = deduce_layout_spec_by_name(enumname); + if (!can_redef_layout_spec(spec, Layout_Enum)) + error(110, enumname, layout_spec_name(spec)); + } } else { lexpush(); /* analyze again */ enumname[0]='\0'; @@ -3997,7 +4466,7 @@ SC_FUNC char *funcdisplayname(char *dest,char *funcname) return dest; } -static void funcstub(int fnative) +static symbol *funcstub(int fnative) { int tok,tag,fpublic; char *str; @@ -4022,7 +4491,7 @@ static void funcstub(int fnative) */ if (numdim == sDIMEN_MAX) { error(53); /* exceeding maximum number of dimensions */ - return; + return NULL; } /* if */ size=needsub(&idxtag[numdim],NULL); /* get size; size==0 for "var[]" */ if (size==0) @@ -4050,12 +4519,12 @@ static void funcstub(int fnative) if (tok==tOPERATOR) { opertok=operatorname(symbolname); if (opertok==0) - return; /* error message already given */ + return NULL; /* error message already given */ check_operatortag(opertok,tag,symbolname); } else { if (tok!=tSYMBOL && freading) { error(10); /* illegal function or declaration */ - return; + return NULL; } /* if */ strcpy(symbolname,str); } /* if */ @@ -4063,7 +4532,7 @@ static void funcstub(int fnative) sym=fetchfunc(symbolname,tag);/* get a pointer to the function entry */ if (sym==NULL) - return; + return NULL; if (fnative) { sym->usage=(char)(uNATIVE | uRETVALUE | uDEFINE | (sym->usage & uPROTOTYPED)); sym->x.lib=curlibrary; @@ -4122,6 +4591,8 @@ static void funcstub(int fnative) litidx=0; /* clear the literal pool */ delete_symbols(&loctab,0,TRUE,TRUE);/* clear local variables queue */ + + return sym; } /* newfunc - begin a function @@ -5364,6 +5835,9 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst) error(203,sym->name); /* symbol isn't used: ... */ } /* if */ break; + case iPROXY: + // Ignore usage on proxies. + break; default: /* a variable */ if (sym->parent!=NULL) @@ -5651,6 +6125,10 @@ static void statement(int *lastindent,int allow_decl) error(3); /* declaration only valid in a block */ } /* if */ break; + case tDELETE: + dodelete(); + lastst=tDELETE; + break; case tDECL: if (allow_decl) { autozero=0; @@ -5675,7 +6153,7 @@ static void statement(int *lastindent,int allow_decl) compound(save==fline,tok); } else { lastst = tEMPTYBLOCK; - } + } /* lastst (for "last statement") does not change you're not my father, don't tell me what to do */ break; diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index 1b5f6cdf..aea32437 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -242,8 +242,6 @@ static void check_empty(const unsigned char *lptr) static void doinclude(int silent) { char name[_MAX_PATH]; - char symname[sNAMEMAX+1]; - char *ptr; char c; int i, result; @@ -1927,9 +1925,10 @@ char *sc_tokens[] = { "||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--", "...", "..", "::", "assert", "*begin", "break", "case", "cellsof", "chars", "const", "continue", "default", - "defined", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", "functag", "goto", - "if", "native", "new", "decl", "operator", "public", "return", "sizeof", - "sleep", "static", "stock", "struct", "switch", "tagof", "*then", "while", + "defined", "delete", "do", "else", "*end", "enum", "exit", "for", "forward", "funcenum", + "functag", "goto", + "if", "int", "methodmap", "native", "new", "decl", "operator", "public", "return", "sizeof", + "sleep", "static", "stock", "struct", "switch", "tagof", "*then", "void", "while", "#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput", "#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma", "#tryinclude", "#undef", @@ -2611,6 +2610,29 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_ constvalue *stateptr; int mustdelete; + // Hack - proxies have a "target" pointer, but the target could be deleted + // already if done inside the main loop below. To get around this we do a + // precursor pass. Note that proxies can only be at the global scope. + if (origRoot == &glbtab) { + symbol *iter = root; + while (iter->next) { + sym = iter->next; + + if (sym->ident != iPROXY) { + iter = sym; + continue; + } + + if (delete_functions || (sym->target->usage & uNATIVE) != 0) { + RemoveFromHashTable(sp_Globals, sym); + iter->next = sym->next; + free_symbol(sym); + } else { + iter = sym; + } + } + } + /* erase only the symbols with a deeper nesting level than the * specified nesting level */ while (root->next!=NULL) { @@ -2653,6 +2675,10 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_ mustdelete=delete_functions || (sym->usage & uNATIVE)!=0; assert(sym->parent==NULL); break; + case iPROXY: + // Original loop determined it was okay to keep. + mustdelete=FALSE; + break; case iARRAYCELL: case iARRAYCHAR: case iEXPRESSION: @@ -2831,6 +2857,10 @@ SC_FUNC symbol *findglb(const char *name,int filter) */ if (sym==NULL) sym=FindInHashTable(sp_Globals,name,fcurrent); + + if (sym && sym->ident == iPROXY) + return sym->target; + return sym; } @@ -3012,3 +3042,18 @@ static char itohstr[30]; return itohstr; } +SC_FUNC int lextok(token_t *tok) +{ + tok->id = lex(&tok->val, &tok->str); + return tok->id; +} + +SC_FUNC int expecttoken(int id, token_t *tok) +{ + int rval = needtoken(id); + if (rval) { + tok->id = tokeninfo(&tok->val, &tok->str); + return rval; + } + return FALSE; +} diff --git a/sourcepawn/compiler/sc3.c b/sourcepawn/compiler/sc3.c index 276c7485..e2236b1a 100644 --- a/sourcepawn/compiler/sc3.c +++ b/sourcepawn/compiler/sc3.c @@ -1,3 +1,4 @@ +/* vim: set ts=8 sts=2 sw=2 tw=99 et: */ /* Pawn compiler - Recursive descend expresion parser * * Copyright (c) ITB CompuPhase, 1997-2005 @@ -56,7 +57,7 @@ static int hier2(value *lval); static int hier1(value *lval1); static int primary(value *lval); static void clear_value(value *lval); -static void callfunction(symbol *sym,value *lval_result,int matchparanthesis); +static void callfunction(symbol *sym, const svalue *implicitthis, value *lval_result, int matchparanthesis); static int dbltest(void (*oper)(),value *lval1,value *lval2); static int commutative(void (*oper)()); static int constant(value *lval); @@ -291,7 +292,7 @@ SC_FUNC int checktags_string(int tags[], int numtags, value *sym1) } for (i=0; itag == pc_tag_string && tags[i] == 0) || - (sym1->tag == 0 && tags[i] == pc_tag_string)) + (sym1->tag == 0 && tags[i] == pc_tag_string)) return TRUE; } return FALSE; @@ -299,13 +300,13 @@ SC_FUNC int checktags_string(int tags[], int numtags, value *sym1) SC_FUNC int checktag_string(value *sym1, value *sym2) { - if (sym1->ident == iARRAY || sym2->ident == iARRAY - || sym1->ident == iREFARRAY || sym2->ident == iREFARRAY) + if (sym1->ident == iARRAY || sym2->ident == iARRAY || + sym1->ident == iREFARRAY || sym2->ident == iREFARRAY) { return FALSE; } - if ((sym1->tag == pc_tag_string && sym2->tag == 0) - || (sym1->tag == 0 && sym2->tag == pc_tag_string)) + if ((sym1->tag == pc_tag_string && sym2->tag == 0) || + (sym1->tag == 0 && sym2->tag == pc_tag_string)) { return TRUE; } @@ -320,191 +321,190 @@ SC_FUNC int matchtag_string(int ident, int tag) return (tag == pc_tag_string) ? TRUE : FALSE; } -SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce) +SC_FUNC int matchtag(int formaltag, int actualtag, int allowcoerce) { - if (formaltag != actualtag) { - /* if the formal tag is zero and the actual tag is not "fixed", the actual - * tag is "coerced" to zero - */ - if (!allowcoerce || formaltag!=0 || (actualtag & FIXEDTAG)!=0) { - if (formaltag == pc_anytag || actualtag == pc_anytag) - { - return TRUE; - } + if (formaltag == actualtag) + return TRUE; - if (formaltag & FUNCTAG) - { - if (actualtag == pc_functag || (formaltag == pc_functag && actualtag & FUNCTAG)) - { - return TRUE; - } else if (actualtag & FUNCTAG) { - constvalue *v = find_tag_byval(actualtag); - int index; - short usage = uPUBLIC; - symbol *sym, *found = NULL; - funcenum_t *e; - functag_t *t; + /* if the formal tag is zero and the actual tag is not "fixed", the actual + * tag is "coerced" to zero + */ + if (allowcoerce && !formaltag && !(actualtag & FIXEDTAG)) + return TRUE; - if (strncmp(v->name, "$Func", 5) != 0) - { - return FALSE; - } + if (formaltag == pc_anytag || actualtag == pc_anytag) + return TRUE; - /* Now we have to go about looking up each function in this enum. WHICH IS IT. */ - e = funcenums_find_byval(formaltag); - if (!e) - { - return FALSE; - } + if (formaltag & FUNCTAG) { + if (actualtag == pc_functag || (formaltag == pc_functag && actualtag & FUNCTAG)) + return TRUE; - assert(v->name[5] == '@' || v->name[5] == '!'); + if (actualtag & FUNCTAG) { + constvalue *v = find_tag_byval(actualtag); + int index; + short usage = uPUBLIC; + symbol *sym, *found = NULL; + funcenum_t *e; + functag_t *t; - /* Deduce which function type this is */ - if (v->name[5] == '@') - { - usage = uPUBLIC; - } else if (v->name[5] == '!') { - usage = uSTOCK; - } + if (strncmp(v->name, "$Func", 5) != 0) + return FALSE; - index = atoi(&v->name[6]); + /* Now we have to go about looking up each function in this enum. WHICH IS IT. */ + e = funcenums_find_byval(formaltag); + if (!e) + return FALSE; - assert(index >= 0); + assert(v->name[5] == '@' || v->name[5] == '!'); - /* Find the function, either by public idx or code addr */ - if (usage == uPUBLIC) - { - for (sym=glbtab.next; sym!=NULL; sym=sym->next) { - if (sym->ident==iFUNCTN && (sym->usage & uPUBLIC)!=0 && (sym->vclass == sGLOBAL)) - { - if (index-- == 0) - { - found = sym; - break; - } - } - } - } else if (usage == uSTOCK) { - for (sym=glbtab.next; sym!=NULL; sym=sym->next) { - if (sym->ident==iFUNCTN && (sym->vclass == sGLOBAL)) - { - if (sym->codeaddr == index) - { - found = sym; - break; - } - } - } - } + /* Deduce which function type this is */ + if (v->name[5] == '@') + { + usage = uPUBLIC; + } else if (v->name[5] == '!') { + usage = uSTOCK; + } - if (!found) - { - assert(found); - return FALSE; - } + index = atoi(&v->name[6]); - /* Wow, we now have: - * 1) The functional enum deduced from formaltag - * 2) The function trying to be shoved in deduced from actualtag - * Now we have to check if it matches any one of the functags inside the enum. - */ - t = e->first; - while (t) - { - int curarg,skip=0,i; - arginfo *func_arg; - funcarg_t *enum_arg; - /* Check return type first. */ - if (t->ret_tag != sym->tag) - { - t = t->next; - continue; - } - /* Check usage */ - if (t->type != usage) - { - t = t->next; - continue; - } - /* Begin iterating arguments */ - for (curarg=0; curargargcount; curarg++) - { - enum_arg = &t->args[curarg]; - /* Check whether we've exhausted our arguments */ - if (sym->dim.arglist[curarg].ident == 0) - { - /* Can we bail out early? */ - if (!enum_arg->ommittable) - { - /* No! */ - skip = 1; - } - break; - } - func_arg = &sym->dim.arglist[curarg]; - /* First check the ident type */ - if (enum_arg->ident != func_arg->ident) - { - skip = 1; - break; - } - /* Next check arrayness */ - if (enum_arg->dimcount != func_arg->numdim) - { - skip = 1; - break; - } - if (enum_arg->dimcount > 0) - { - for (i=0; idimcount; i++) - { - if (enum_arg->dims[i] != func_arg->dim[i]) - { - skip = 1; - break; - } - } - if (skip) - { - break; - } - } - /* Lastly, check the tags */ - if (enum_arg->tagcount != func_arg->numtags) - { - skip = 1; - break; - } - /* They should all be in the same order just for clarity... */ - for (i=0; itagcount; i++) - { - if (enum_arg->tags[i] != func_arg->tags[i]) - { - skip = 1; - break; - } - } - if (skip) - { - break; - } - } - if (!skip) - { - /* Make sure there are no trailing arguments */ - if (sym->dim.arglist[curarg].ident == 0) - { - return TRUE; - } - } - t = t->next; - } - } - } - return FALSE; - } - } /* if */ - return TRUE; + assert(index >= 0); + + /* Find the function, either by public idx or code addr */ + if (usage == uPUBLIC) + { + for (sym=glbtab.next; sym!=NULL; sym=sym->next) { + if (sym->ident==iFUNCTN && (sym->usage & uPUBLIC)!=0 && (sym->vclass == sGLOBAL)) + { + if (index-- == 0) + { + found = sym; + break; + } + } + } + } else if (usage == uSTOCK) { + for (sym=glbtab.next; sym!=NULL; sym=sym->next) { + if (sym->ident==iFUNCTN && (sym->vclass == sGLOBAL)) + { + if (sym->codeaddr == index) + { + found = sym; + break; + } + } + } + } + + if (!found) + { + assert(found); + return FALSE; + } + + /* Wow, we now have: + * 1) The functional enum deduced from formaltag + * 2) The function trying to be shoved in deduced from actualtag + * Now we have to check if it matches any one of the functags inside the enum. + */ + t = e->first; + while (t) + { + int curarg,skip=0,i; + arginfo *func_arg; + funcarg_t *enum_arg; + /* Check return type first. */ + if (t->ret_tag != sym->tag) + { + t = t->next; + continue; + } + /* Check usage */ + if (t->type != usage) + { + t = t->next; + continue; + } + /* Begin iterating arguments */ + for (curarg=0; curargargcount; curarg++) + { + enum_arg = &t->args[curarg]; + /* Check whether we've exhausted our arguments */ + if (sym->dim.arglist[curarg].ident == 0) + { + /* Can we bail out early? */ + if (!enum_arg->ommittable) + { + /* No! */ + skip = 1; + } + break; + } + func_arg = &sym->dim.arglist[curarg]; + /* First check the ident type */ + if (enum_arg->ident != func_arg->ident) + { + skip = 1; + break; + } + /* Next check arrayness */ + if (enum_arg->dimcount != func_arg->numdim) + { + skip = 1; + break; + } + if (enum_arg->dimcount > 0) + { + for (i=0; idimcount; i++) + { + if (enum_arg->dims[i] != func_arg->dim[i]) + { + skip = 1; + break; + } + } + if (skip) + break; + } + /* Lastly, check the tags */ + if (enum_arg->tagcount != func_arg->numtags) + { + skip = 1; + break; + } + /* They should all be in the same order just for clarity... */ + for (i=0; itagcount; i++) + { + if (enum_arg->tags[i] != func_arg->tags[i]) + { + skip = 1; + break; + } + } + if (skip) + break; + } + if (!skip) + { + /* Make sure there are no trailing arguments */ + if (sym->dim.arglist[curarg].ident == 0) + return TRUE; + } + t = t->next; + } + } + } + + // See if the tag has a methodmap associated with it. If so, see if the given + // tag is anywhere on the inheritance chain. + methodmap_t *map = methodmap_find_by_tag(actualtag); + if (map) { + for (; map; map = map->parent) { + if (map->tag == formaltag) + return TRUE; + } + } + + return FALSE; } /* @@ -1583,7 +1583,7 @@ static int hier2(value *lval) if (subsym!=NULL) subsym=finddepend(subsym); } /* for */ - if (level>sym->dim.array.level+1) { + if (level>sym->dim.array.level+1) { error(28,sym->name); /* invalid subscript */ } else if (level==sym->dim.array.level+1) { lval->constval=(idxsym!=NULL && idxsym->dim.array.length>0) ? idxsym->dim.array.length : 1; @@ -1637,7 +1637,7 @@ static int hier2(value *lval) if (subsym!=NULL) subsym=finddepend(subsym); } /* for */ - if (level>sym->dim.array.level+1) { + if (level>sym->dim.array.level+1) { error(28,sym->name); /* invalid subscript */ } else if (level==sym->dim.array.level+1) { lval->constval= (idxsym!=NULL && idxsym->dim.array.length>0) ? idxsym->dim.array.length : 1; @@ -1812,7 +1812,7 @@ static int hier1(value *lval1) cursym=lval1->sym; restart: sym=cursym; - if (matchtoken('[') || matchtoken('{') || matchtoken('(')) { + if (matchtoken('[') || matchtoken('{') || matchtoken('(') || matchtoken('.')) { tok=tokeninfo(&val,&st); /* get token read by matchtoken() */ magic_string = (sym && (sym->tag == pc_tag_string && sym->dim.array.level == 0)); if (sym==NULL && symtok!=tSYMBOL) { @@ -1974,14 +1974,66 @@ restart: lval1->tag=sym->tag; lval1->constval=0; } /* if */ + + // If there's a call coming up, keep parsing. + if (matchtoken('.')) { + lexpush(); + goto restart; + } + /* a cell in an array is an lvalue, a character in an array is not * always a *valid* lvalue */ return TRUE; } else { /* tok=='(' -> function(...) */ + svalue thisval; + thisval.val = *lval1; + thisval.lvalue = lvalue; + + svalue *implicitthis = NULL; + if (tok == '.') { + methodmap_t *map; + + /* Catch invalid calls early so we don't compile with a tag mismatch. */ + switch (thisval.val.ident) { + case iARRAY: + case iREFARRAY: + error(106); + break; + + case iFUNCTN: + case iREFFUNC: + error(107); + break; + } + + if ((map = methodmap_find_by_tag(thisval.val.tag)) == NULL) { + error(104, pc_tagname(thisval.val.tag)); + } + + if (needtoken(tSYMBOL) && map) { + cell lexval; + char *lexstr; + methodmap_method_t *method; + + tokeninfo(&lexval, &lexstr); + if ((method = methodmap_find_method(map, lexstr)) == NULL) + error(105, map->name, lexstr); + if (method) { + implicitthis = &thisval; + sym = method->target; + } + } + + // If we don't find a '(' next, just fail to compile for now -- and + // don't even try to do a function call, just restart the parse loop. + if (!needtoken('(')) + goto restart; + + tok = '('; + } + assert(tok=='('); - if (sym==NULL - || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC)) - { + if (sym==NULL || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC)) { if (sym==NULL && sc_status==statFIRST) { /* could be a "use before declaration"; in that case, create a stub * function so that the usage can be marked. @@ -1998,14 +2050,14 @@ restart: funcdisplayname(symname,sym->name); error(4,symname); /* function not defined */ } /* if */ - callfunction(sym,lval1,TRUE); + callfunction(sym,implicitthis,lval1,TRUE); return FALSE; /* result of function call is no lvalue */ } /* if */ } /* if */ if (sym!=NULL && lval1->ident==iFUNCTN) { assert(sym->ident==iFUNCTN); if (sc_allowproccall) { - callfunction(sym,lval1,FALSE); + callfunction(sym,NULL,lval1,FALSE); } else if ((sym->usage & uNATIVE) != uNATIVE) { symbol *oldsym=sym; int n=-1,iter=0; @@ -2036,14 +2088,14 @@ restart: } lval1->tag=pc_addfunctag(faketag); oldsym->usage |= uREAD; - sym->usage |= uREAD; + sym->usage |= uREAD; } else { error(76); /* invalid function call, or syntax error */ } /* if */ return FALSE; - } else { - error(76); /* invalid function call, or syntax error */ - } + } else { + error(76); /* invalid function call, or syntax error */ + } } /* if */ return lvalue; } @@ -2243,7 +2295,7 @@ enum { * Generates code to call a function. This routine handles default arguments * and positional as well as named parameters. */ -static void callfunction(symbol *sym,value *lval_result,int matchparanthesis) +static void callfunction(symbol *sym, const svalue *implicitthis, value *lval_result, int matchparanthesis) { static long nest_stkusage=0L; static int nesting=0; @@ -2261,6 +2313,7 @@ static int nesting=0; symbol *symret; cell lexval; char *lexstr; + int pending_this = (implicitthis ? TRUE : FALSE); assert(sym!=NULL); lval_result->ident=iEXPRESSION; /* preset, may be changed later */ @@ -2321,9 +2374,9 @@ static int nesting=0; lexpush(); /* reset the '.' */ } /* if */ } /* if */ - if (!close) { + if (pending_this || !close) { do { - if (matchtoken('.')) { + if (!pending_this && matchtoken('.')) { namedparams=TRUE; if (needtoken(tSYMBOL)) tokeninfo(&lexval,&lexstr); @@ -2350,7 +2403,7 @@ static int nesting=0; stgmark((char)(sEXPRSTART+argpos));/* mark beginning of new expression in stage */ if (arglist[argpos]!=ARG_UNHANDLED) error(58); /* argument already set */ - if (matchtoken('_')) { + if (!pending_this && matchtoken('_')) { arglist[argpos]=ARG_IGNORED; /* flag argument as "present, but ignored" */ if (arg[argidx].ident==0 || arg[argidx].ident==iVARARGS) { error(92); /* argument count mismatch */ @@ -2368,7 +2421,12 @@ static int nesting=0; arglist[argpos]=ARG_DONE; /* flag argument as "present" */ if (arg[argidx].ident!=0 && arg[argidx].numtags==1) /* set the expected tag, if any */ lval.cmptag=arg[argidx].tags[0]; - lvalue=hier14(&lval); + if (pending_this) { + lval = implicitthis->val; + lvalue = implicitthis->lvalue; + } else { + lvalue = hier14(&lval); + } assert(sc_status==statFIRST || arg[argidx].ident == 0 || arg[argidx].tags!=NULL); switch (arg[argidx].ident) { case 0: @@ -2428,14 +2486,14 @@ static int nesting=0; /* otherwise, the expression result is already in PRI */ assert(arg[argidx].numtags>0); check_userop(NULL,lval.tag,arg[argidx].tags[0],2,NULL,&lval.tag); - if (!checktags_string(arg[argidx].tags, arg[argidx].numtags, &lval) - && !checktag(arg[argidx].tags,arg[argidx].numtags,lval.tag)) - { - if (arg[argidx].numtags == 1 && arg[argidx].tags[0] & FUNCTAG) + if (!checktags_string(arg[argidx].tags, arg[argidx].numtags, &lval) && + !checktag(arg[argidx].tags, arg[argidx].numtags, lval.tag)) + { + if (arg[argidx].numtags == 1 && arg[argidx].tags[0] & FUNCTAG) error(100); /* error - function prototypes do not match */ - else + else error(213); /* warning - tag mismatch */ - } + } if (lval.tag!=0) append_constval(&taglst,arg[argidx].name,lval.tag,0); argidx++; /* argument done */ @@ -2547,18 +2605,32 @@ static int nesting=0; } /* if */ assert(arglist[argpos]!=ARG_UNHANDLED); nargs++; + + /** + * We can already have decided it was time to close because of pending_this. + * If that's the case, then bail out now. + */ + if (pending_this && close) { + pending_this = FALSE; + break; + } + if (matchparanthesis) { close=matchtoken(')'); if (!close) /* if not paranthese... */ - if (!needtoken(',')) /* ...should be comma... */ + /* Not expecting comma if the first argument was implicit. */ + if (!pending_this && !needtoken(',')) break; /* ...but abort loop if neither */ } else { - close=!matchtoken(','); + /* Not expecting comma if the first argument was implicit. */ + close = (!pending_this && !matchtoken(',')); if (close) { /* if not comma... */ if (needtoken(tTERM)==1)/* ...must be end of statement */ lexpush(); /* push again, because end of statement is analised later */ } /* if */ } /* if */ + + pending_this = FALSE; } while (!close && freading && !matchtoken(tENDEXPR)); /* do */ } /* if */ /* check remaining function arguments (they may have default values) */ @@ -2797,7 +2869,7 @@ static int constant(value *lval) * value distinguishes between literal arrays * and literal strings (this was done for * array assignment). */ - lval->tag=pc_tag_string; + lval->tag=pc_tag_string; } else if (tok=='{') { int tag,lasttag=-1; val=litidx; diff --git a/sourcepawn/compiler/sc5.c b/sourcepawn/compiler/sc5.c index 62a936ea..1b7dd665 100644 --- a/sourcepawn/compiler/sc5.c +++ b/sourcepawn/compiler/sc5.c @@ -52,8 +52,8 @@ static unsigned char warndisable[(NUM_WARNINGS + 7) / 8]; /* 8 flags in a char */ static int errflag; -static int errstart; /* line number at which the instruction started */ -static int errline; /* forced line number for the error message */ +static int errstart; /* line number at which the instruction started */ +static int sErrLine; /* forced line number for the error message */ /* error * @@ -75,6 +75,12 @@ static short lastfile; char *msg,*pre; va_list argptr; + // sErrLine is used to temporarily change the line number of reported errors. + // Pawn has an upstream bug where this is not reset on early-return, which + // can lead to broken line numbers in error messages. + int errline = sErrLine; + sErrLine = -1; + /* errflag is reset on each semicolon. * In a two-pass compiler, an error should not be reported twice. Therefore * the error reporting is enabled only in the second pass (and only when @@ -148,7 +154,6 @@ static short lastfile; longjmp(errbuf,2); /* fatal error, quit */ } /* if */ - errline=-1; /* check whether we are seeing many errors on the same line */ if ((errstart<0 && lastline!=fline) || lastlinefline || fcurrent!=lastfile) errorcount=0; @@ -176,10 +181,10 @@ SC_FUNC void errorset(int code,int line) break; case sEXPRRELEASE: errstart=-1; /* forget start line number */ - errline=-1; + sErrLine=-1; break; case sSETPOS: - errline=line; + sErrLine=line; break; } /* switch */ } diff --git a/sourcepawn/compiler/sc5.scp b/sourcepawn/compiler/sc5.scp index 6d32eb5b..68437f28 100644 --- a/sourcepawn/compiler/sc5.scp +++ b/sourcepawn/compiler/sc5.scp @@ -1,361 +1,407 @@ -/* Pawn compiler - Error message strings (plain and compressed formats) - * - * Copyright (c) ITB CompuPhase, 2000-2006 - * - * This software is provided "as-is", without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in - * a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * Version: $Id$ - */ - -SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned char pairtable[128][2]); - -#define SCPACK_TABLE errstr_table -/*-*SCPACK start of pair table, do not change or remove this line */ -unsigned char errstr_table[][2] = { - {101,32}, {111,110}, {116,32}, {105,110}, {97,114}, {115,32}, {116,105}, {100,32}, {101,114}, {37,115}, {101,110}, {134,129}, {34,137}, {140,34}, {97,108}, {117,110}, - {114,101}, {110,111}, {97,116}, {115,105}, {121,32}, {97,110}, {111,114}, {109,98}, {115,116}, {32,141}, {100,101}, {41,10}, {109,138}, {145,130}, {101,135}, {139,32}, - {98,108}, {111,108}, {114,97}, {143,99}, {118,142}, {102,163}, {115,121}, {166,151}, {167,161}, {97,32}, {117,115}, {103,32}, {115,147}, {132,162}, {97,160}, {136,32}, - {150,32}, {99,104}, {103,117}, {105,135}, {178,156}, {164,179}, {132,180}, {111,102}, {116,104}, {101,120}, {165,159}, {131,181}, {101,100}, {101,133}, {105,133}, {168,153}, - {154,102}, {118,132}, {183,32}, {105,174}, {193,195}, {116,111}, {173,148}, {109,97}, {99,129}, {101,10}, {115,10}, {112,144}, {116,97}, {182,130}, {98,128}, {152,146}, - {44,32}, {132,97}, {192,131}, {170,130}, {153,10}, {109,146}, {191,155}, {109,211}, {40,214}, {104,97}, {196,128}, {34,32}, {129,32}, {142,32}, {105,99}, {117,108}, - {99,111}, {147,122}, {110,32}, {100,105}, {101,108}, {108,111}, {111,112}, {116,136}, {200,152}, {131,32}, {149,32}, {131,171}, {213,177}, {58,212}, {109,101}, {102,105}, - {100,111}, {97,115}, {108,128}, {118,128}, {230,136}, {232,149}, {204,171}, {203,172}, {215,206}, {119,105}, {109,112}, {110,117}, {185,247}, {165,139}, {251,151} -}; -/*-*SCPACK end of pair table, do not change or remove this line */ - -static char *errmsg[] = { -#if 1 -/*001*/ "expected token: \"%s\", but found \"%s\"\n", -/*002*/ "only a single statement (or expression) can follow each \"case\"\n", -/*003*/ "declaration of a local variable must appear in a compound block\n", -/*004*/ "function \"%s\" is not implemented\n", -/*005*/ "function may not have arguments\n", -/*006*/ "must be assigned to an array\n", -/*007*/ "operator cannot be redefined\n", -/*008*/ "must be a constant expression; assumed zero\n", -/*009*/ "invalid array size (negative, zero or out of bounds)\n", -/*010*/ "invalid function or declaration\n", -/*011*/ "invalid outside functions\n", -/*012*/ "invalid function call, not a valid address\n", -/*013*/ "no entry point (no public functions)\n", -/*014*/ "invalid statement; not in switch\n", -/*015*/ "\"default\" case must be the last case in switch statement\n", -/*016*/ "multiple defaults in \"switch\"\n", -/*017*/ "undefined symbol \"%s\"\n", -/*018*/ "initialization data exceeds declared size\n", -/*019*/ "not a label: \"%s\"\n", -/*020*/ "invalid symbol name \"%s\"\n", -/*021*/ "symbol already defined: \"%s\"\n", -/*022*/ "must be lvalue (non-constant)\n", -/*023*/ "array assignment must be simple assignment\n", -/*024*/ "\"break\" or \"continue\" is out of context\n", -/*025*/ "function heading differs from prototype\n", -/*026*/ "no matching \"#if...\"\n", -/*027*/ "invalid character constant\n", -/*028*/ "invalid subscript (not an array or too many subscripts): \"%s\"\n", -/*029*/ "invalid expression, assumed zero\n", -/*030*/ "compound statement not closed at the end of file (started at line %d)\n", -/*031*/ "unknown directive\n", -/*032*/ "array index out of bounds (variable \"%s\")\n", -/*033*/ "array must be indexed (variable \"%s\")\n", -/*034*/ "argument does not have a default value (argument %d)\n", -/*035*/ "argument type mismatch (argument %d)\n", -/*036*/ "empty statement\n", -/*037*/ "invalid string (possibly non-terminated string)\n", -/*038*/ "extra characters on line\n", -/*039*/ "constant symbol has no size\n", -/*040*/ "duplicate \"case\" label (value %d)\n", -/*041*/ "invalid ellipsis, array size is not known\n", -/*042*/ "invalid combination of class specifiers\n", -/*043*/ "character constant exceeds range for packed string\n", -/*044*/ "positional parameters must precede all named parameters\n", -/*045*/ "too many function arguments\n", -/*046*/ "unknown array size (variable \"%s\")\n", -/*047*/ "array sizes do not match, or destination array is too small\n", -/*048*/ "array (s do not match\n", -/*049*/ "invalid line continuation\n", -/*050*/ "invalid range\n", -/*051*/ "invalid subscript, use \"[ ]\" operators on major dimensions\n", -/*052*/ "multi-dimensional arrays must be fully initialized\n", -/*053*/ "exceeding maximum number of dimensions\n", -/*054*/ "unmatched closing brace (\"}\")\n", -/*055*/ "start of function body without function header\n", -/*056*/ "arrays, local variables and function arguments cannot be public (variable \"%s\")\n", -/*057*/ "unfinished expression before compiler directive\n", -/*058*/ "duplicate argument; same argument is passed twice\n", -/*059*/ "function argument may not have a default value (variable \"%s\")\n", -/*060*/ "multiple \"#else\" directives between \"#if ... #endif\"\n", -/*061*/ "\"#elseif\" directive follows an \"#else\" directive\n", -/*062*/ "number of operands does not fit the operator\n", -/*063*/ "function result tag of operator \"%s\" must be \"%s\"\n", -/*064*/ "cannot change predefined operators\n", -/*065*/ "function argument may only have a single tag (argument %d)\n", -/*066*/ "function argument may not be a reference argument or an array (argument \"%s\")\n", -/*067*/ "variable cannot be both a reference and an array (variable \"%s\")\n", -/*068*/ "invalid rational number precision in #pragma\n", -/*069*/ "rational number format already defined\n", -/*070*/ "rational number support was not enabled\n", -/*071*/ "user-defined operator must be declared before use (function \"%s\")\n", -/*072*/ "\"sizeof\" operator is invalid on \"function\" symbols\n", -/*073*/ "function argument must be an array (argument \"%s\")\n", -/*074*/ "#define pattern must start with an alphabetic character\n", -/*075*/ "input line too long (after substitutions)\n", -/*076*/ "syntax error in the expression, or invalid function call\n", -/*077*/ "malformed UTF-8 encoding, or corrupted file: %s\n", -/*078*/ "function uses both \"return\" and \"return \"\n", -/*079*/ "inconsistent return types (array & non-array)\n", -/*080*/ "unknown symbol, or not a constant symbol (symbol \"%s\")\n", -/*081*/ "cannot take a tag as a default value for an indexed array parameter (symbol \"%s\")\n", -/*082*/ "user-defined operators and native functions may not have states\n", -/*083*/ "a function or variable may only belong to a single automaton (symbol \"%s\")\n", -/*084*/ "state conflict: one of the states is already assigned to another implementation (symbol \"%s\")\n", -/*085*/ "no states are defined for symbol \"%s\"\n", -/*086*/ "unknown automaton \"%s\"\n", -/*087*/ "unknown state \"%s\" for automaton \"%s\"\n", -/*088*/ "public variables and local variables may not have states (symbol \"%s\")\n", -/*089*/ "state variables may not be initialized (symbol \"%s\")\n", -/*090*/ "public functions may not return arrays (symbol \"%s\")\n", -/*091*/ "ambiguous constant; tag override is required (symbol \"%s\")\n", -/*092*/ "number of arguments does not match definition\n", -/*093*/ "expected tag name identifier\n", -/*094*/ "function enumeration requires unique tag\n", -/*095*/ "cannot have required parameters after optional parameters\n", -/*096*/ "could not find member \"%s\" in struct \"%s\"\n", -/*097*/ "symbol \"%s\" does not have a matching type\n", -/*098*/ "struct requires unique struct name\n", -/*099*/ "member \"%s\" appears more than once in struct \"%s\"\n", -/*100*/ "function prototypes do not match\n", -/*101*/ "specify either all dimensions or only the last dimension\n" -#else - "\271pect\236\305k\212:\231\320bu\202fo\217\207\215\012", - "\201l\224\251s\203g\362\317e\234\202(\260\374\201) c\352f\241\345w ea\261 \042c\361e\042\012", - "\232cl\321\237\302\251\345c\335\332\327appe\204 \351\251\340\372o\217\207\240ock\012", - "\375\231 \276\235i\372le\234t\274\012", - "\272\307\224\235\331\363\266t\312", - "\370a\254gn\236\305 \352\255y\012", - "\364\222\260c\225\235\316\220\322\274\012", - "\370\251\365\202\374\201; \361sum\236z\210o\012", - "\273\306\341\200(nega\206ve\320z\210o \260ou\202\302bo\217ds\233", - "\273\272\260\232cl\321\213\012", - "\273out\223d\200\375\312", - "\273\272c\216l\320\235\251\265add\220s\312", - "\221 \212tr\224po\203\202(\221 pu\240\336 \375s\233", - "\273\317e\234t; \235\351s\371t\261\012", - "\042\300a\337t\333c\361\200\370\270\200l\361\202c\361\200\351s\371t\261 \317e\234t\012", - "m\337\206p\362\300a\337t\205\351\042s\371t\261\042\012", - "\217\322\236\277\012", - "\203i\206\216iza\237d\222\251\271ce\274\205\232cl\204\236\341\311", - "\235\251lab\344\355", - "\273\250 nam\200\215\012", - "\250 \216\220ad\224\322\274\355", - "\370l\244u\200(n\201-\365t\233", - "\306a\254gn\234\202\370\223\372\362a\254gn\234t\012", - "\042b\220ak\333\260\042\310t\203ue\333\276ou\202\302\310t\271t\012", - "\272head\353\343ff\210\205from pro\305typ\311", - "\221 \354\353\042#if...\042\012", - "\273\261\321ct\257\365t\012", - "\273subscrip\202(\235\352\306\260\305o m\225\224subscripts)\355", - "\273\374\201\320\361sum\236z\210o\012", - "\340\372o\217\207\317e\234\202\235c\345s\236a\202\270\200\212\207\302\357\362(\230\204t\236a\202l\203\200%d\233", - "\217k\221w\342\343\220c\206v\311", - "\306\203\232x ou\202\302bo\217d\205(\332\215\233", - "\306\370\203\232x\236(\332\215\233", - "\315\360\275\235\331\363\251\300a\337\202\244u\200(\315%d\233", - "\315typ\200mis\354 (\315%d\233", - "e\372t\224\317e\234t\012", - "\273\230r\353(po\254\240\224n\201-\347m\203\222\236\230r\203g\233", - "\271t\242 \261\321c\347\205\334l\203\311", - "\365\202\250 \331\205\221 \341\311", - "dupl\336\222\200\042c\361e\333lab\344 (\244u\200%d\233", - "\273\344lip\223s\320\306\341\200\276\235k\221wn\012", - "\273\340\227\203a\237\302cl\361\205speci\357\210\312", - "\261\321ct\257\365\202\271ce\274\205r\225g\200f\260pack\236\230r\203g\012", - "po\223\213\335p\321\356\347\205\327\313c\274\200\216l nam\236p\321\356\347\312", - "\305o m\225\224\272\266t\312", - "\217k\221w\342\306\341\200(\332\215\233", - "\306\341\275\360 \235\354\320\260\232\230\203a\237\306\276\305o sm\216l\012", - "\306(\205\360 \235\354\012", - "\273l\203\200\310t\203ua\213\012", - "\273r\225g\311", - "\273subscript\320\252\200\042[ ]\333\364\222\226\205\334\307j\260\343\234\223\201\312", - "m\337\206-\343\234\223\201\335\255y\205\370f\337l\224\203i\206\216iz\274\012", - "\271ce\274\353\307ximum \376\257\302\343\234\223\201\312", - "\217\354\236c\345s\353b\242c\200(\042}\042\233", - "\230\204\202\302\272bod\224\371\270ou\202\272head\210\012", - "\255ys\320\345c\335\304\275\225\207\272\266t\205c\225\235\316pu\240\336 (\332\215\233", - "\217f\203ish\236\374\334bef\226\200\340\372il\257\343\220c\206v\311", - "dupl\336\222\200\266t; sam\200\315\276p\361s\236tw\336\311", - "\272\315\307\224\235\331\363\251\300a\337\202\244u\200(\332\215\233", - "m\337\206p\362\042#\344se\333\343\220c\206v\275betwe\212 \042#if ... #\212\343f\042\012", - "\042#\344seif\333\343\220c\206\363f\241\345w\205\352\042#\344se\333\343\220c\206v\311", - "\376\257\302\364\225d\205\360\275\235\357\202\270\200\364\222\226\012", - "\272\220s\337\202\366\302\364\222\226\231 \370\215\012", - "c\225\235\261\225g\200\313\322\236\364\222\226\312", - "\272\315\307\224\201l\224\331\363\251s\203g\362\366(\315%d\233", - "\272\315\307\224\235\316\251\220f\210\212c\200\315\260\352\306(\315\215\233", - "\332c\225\235\316bo\270 \251\220f\210\212c\200\225\207\352\306(\332\215\233", - "\273\242\213\335\376\257\313ci\223\334\351#p\242g\307\012", - "\242\213\335\376\257f\226\307\202\216\220ad\224\322\274\012", - "\242\213\335\376\257supp\226\202wa\205\235\212\256\274\012", - "\252\210-\322\236\364\222\260\370\232cl\204\236bef\226\200\252\200(\375\231\233", - "\042\341e\267\333\364\222\260\276\273\334\042\375\333\250\312", - "\272\315\370\352\306(\315\215\233", - "#\322\200p\222\347\342\327\230\204\202\371\270 \352\216p\331be\206c \261\321c\347\012", - "\203pu\202l\203\200\305o l\201\253(aft\257subs\206tu\213s\233", - "\246n\314x \210r\260\351\270\200\374\201\320\260\273\272c\216l\012", - "m\216f\226m\236UTF-8 \212\340d\203g\320\260c\226rupt\236\357le: \211\012", - "\272\252\275bo\270 \042\220turn\333\225\207\042\220tur\342<\244ue>\042\012", - "\203\310\223\230\212\202\220tur\342typ\275(\306& n\201-\255y\233", - "\217k\221w\342\250\320\260\235\251\365\202\250 \330", - "c\225\235\314k\200\251\366a\205\251\300a\337\202\244u\200f\260\352\203\232x\236\306p\321\356t\257\330", - "\252\210-\322\236\364\222\226\205\225\207na\206\363\375\205\307\224\235\331\363\317e\312", - "\251\272\260\332\307\224\201l\224b\344\201\253\305 \251s\203g\362au\305\325\334\330", - "\317\200\310fl\336t: \201\200\302\270\200\317\275\276\216\220ad\224a\254gn\236\305 a\221\270\257i\372le\234\314\237\330", - "\221 \317\275\204\200\322\236f\260\277\012", - "\217k\221w\342au\305\325\201\324", - "\217k\221w\342\317\200\215 f\260au\305\325\201\324", - "pu\240\336 \304\275\225\207\345c\335\304\275\307\224\235\331\363\317\275\330", - "\317\200\304\275\307\224\235\316\203i\206\216iz\236\330", - "pu\240\336 \375\205\307\224\235\220tur\342\255y\205\330", - "a\227i\262ou\205\365t; \366ov\210rid\200\276\220qui\220\207\330", - "\376\257\302\266t\205\360\275\235\354 \322i\213\012", - "\271pect\236\366nam\200id\212\206\357\210\012", - "\272\212um\210a\237\220qui\220\205\217iqu\200\314g\012", - "c\225\235\331\363\220qui\220\207p\321\356\347\205aft\257\346\213\335p\321\356\347\312", - "\340\337\207\235f\203\207\356\227\210\231 \351\230ruc\202\215\012", - "\277 \360\275\235\331\363\251\354\353typ\311", - "\230ruc\202\220qui\220\205\217iqu\200\230ruc\202nam\311", - "\356\227\210\231 appe\204\205m\226\200\270\352\201c\200\351\230ruc\202\215\012", - "\272pro\305typ\275\360 \235\354\012" -#endif - }; - -static char *fatalmsg[] = { -#if 1 -/*120*/ "cannot read from file: \"%s\"\n", -/*121*/ "cannot write to file: \"%s\"\n", -/*122*/ "table overflow: \"%s\"\n", - /* table can be: loop table - * literal table - * staging buffer - * option table (response file) - * peephole optimizer table - */ -/*123*/ "insufficient memory\n", -/*124*/ "invalid assembler instruction \"%s\"\n", -/*125*/ "numeric overflow, exceeding capacity\n", -/*126*/ "compiled script exceeds the maximum memory size (%ld bytes)\n", -/*127*/ "too many error messages on one line\n", -/*128*/ "codepage mapping file not found\n", -/*129*/ "invalid path: \"%s\"\n", -/*130*/ "assertion failed: %s\n", -/*131*/ "user error: %s\n", -#else - "c\225\235\220a\207from \357le\355", - "c\225\235writ\200\305 \357le\355", - "t\256\200ov\210f\345w\355", - "\203suff\336i\212\202\356m\226y\012", - "\273\361se\227l\257\203\230ruc\213\324", - "\373m\210\336 ov\210f\345w\320\271ce\274\353capacity\012", - "\340\372il\236scrip\202\271ce\274\205\270\200\307ximum \356m\226\224\341\200(%l\207bytes\233", - "\305o m\225\224\210r\260\356ssag\275\334\201\200l\203\311", - "\340\232pag\200\307pp\353\357\362\235fo\217d\012", - "\273p\222h\355", - "\361s\210\237fail\274: \211\012", - "\252\257\210r\226: \211\012" -#endif - }; - -static char *warnmsg[] = { -#if 1 -/*200*/ "symbol \"%s\" is truncated to %d characters\n", -/*201*/ "redefinition of constant/macro (symbol \"%s\")\n", -/*202*/ "number of arguments does not match definition\n", -/*203*/ "symbol is never used: \"%s\"\n", -/*204*/ "symbol is assigned a value that is never used: \"%s\"\n", -/*205*/ "redundant code: constant expression is zero\n", -/*206*/ "redundant test: constant expression is non-zero\n", -/*207*/ "unknown #pragma\n", -/*208*/ "function with tag result used before definition, forcing reparse\n", -/*209*/ "function \"%s\" should return a value\n", -/*210*/ "possible use of symbol before initialization: \"%s\"\n", -/*211*/ "possibly unintended assignment\n", -/*212*/ "possibly unintended bitwise operation\n", -/*213*/ "tag mismatch\n", -/*214*/ "possibly a \"const\" array argument was intended: \"%s\"\n", -/*215*/ "expression has no effect\n", -/*216*/ "nested comment\n", -/*217*/ "loose indentation\n", -/*218*/ "old style prototypes used with optional semicolumns\n", -/*219*/ "local variable \"%s\" shadows a variable at a preceding level\n", -/*220*/ "expression with tag override must appear between parentheses\n", -/*221*/ "label name \"%s\" shadows tag name\n", -/*222*/ "number of digits exceeds rational number precision\n", -/*223*/ "redundant \"sizeof\": argument size is always 1 (symbol \"%s\")\n", -/*224*/ "indeterminate array size in \"sizeof\" expression (symbol \"%s\")\n", -/*225*/ "unreachable code\n", -/*226*/ "a variable is assigned to itself (symbol \"%s\")\n", -/*227*/ "more initializers than enum fields\n", -/*228*/ "length of initializer exceeds size of the enum field\n", -/*229*/ "index tag mismatch (symbol \"%s\")\n", -/*230*/ "no implementation for state \"%s\" in function \"%s\", no fall-back\n", -/*231*/ "state specification on forward declaration is ignored\n", -/*232*/ "output file is written, but with compact encoding disabled\n", -/*233*/ "state variable \"%s\" shadows a global variable\n", -/*234*/ "symbol \"%s\" is marked as deprecated: %s\n", -/*235*/ "public function lacks forward declaration (symbol \"%s\")\n", -/*236*/ "unknown parameter in substitution (incorrect #define pattern)\n" -#else - "\277 \276tr\243\222\236\305 %\207\261\321c\347\312", - "\220\322i\237\302\365t/\307cro \330", - "\376\257\302\266t\205\360\275\235\354 \322i\213\012", - "\250 \276nev\257\252\274\355", - "\250 \276a\254gn\236\251\244u\200\270a\202\276nev\257\252\274\355", - "\220d\217d\225\202\340\232: \365\202\374\334\276z\210o\012", - "\220d\217d\225\202te\230: \365\202\374\334\276n\201-z\210o\012", - "\217k\221w\342#p\242g\307\012", - "\272\371\270 \366\220s\337\202\252\236bef\226\200\322i\213\320f\226c\353\220p\204s\311", - "\375\231 sho\337\207\220tur\342\251\244u\311", - "po\254\240\200\252\200\302\250 bef\226\200\203i\206\216iza\213\355", - "po\254\240\224\217\203t\212\232\207a\254gn\234t\012", - "po\254\240\224\217\203t\212\232\207bit\371s\200\364a\213\012", - "\366mis\354\012", - "po\254\240\224\251\042\350\333\306\315wa\205\203t\212\232d\355", - "\374\334\331\205\221 effect\012", - "ne\230\236\340m\234t\012", - "\345os\200\203d\212\314\213\012", - "\241\207\230y\362pro\305typ\275\252\236\371\270 \346\213\335sem\336\241umn\312", - "\345c\335\332\215 s\331\360w\205\251\332a\202\251\313c\274\353lev\344\012", - "\374\334\371\270 \366ov\210rid\200\327appe\204 betwe\212 p\204\212\270ese\312", - "lab\344 nam\200\215 s\331\360w\205\366nam\311", - "\376\257\302\343git\205\271ce\274\205\242\213\335\376\257\313ci\223\201\012", - "\220d\217d\225\202\042\341e\267\042: \315\341\200\276\216way\2051 \330", - "\203\232\347m\203\222\200\306\341\200\351\042\341e\267\333\374\334\330", - "\217\220a\261\256\200\340\232\012", - "\251\332\276a\254gn\236\305 its\344f \330", - "m\226\200\203i\206\216iz\210\205\270\352\212um \357\344d\312", - "l\212g\270 \302\203i\206\216iz\257\271ce\274\205\341\200\302\270\200\212um \357\344d\012", - "\203\232x \366mis\354 \330", - "\221 i\372le\234\314\237f\260\317\200\215 \351\375\231\320\221 f\216l-back\012", - "\317\200specif\336a\237\334f\226w\204\207\232cl\321\237\276ig\221\220d\012", - "outpu\202\357\362\276writt\212\320bu\202\371\270 \340\372ac\202\212\340d\353\343s\256\274\012", - "\317\200\332\215 s\331\360w\205\251g\345b\335\304\311", - "\277 \276m\204k\236a\205\232\313c\222\274: \211\012", - "pu\240\336 \272lack\205f\226w\204\207\232cl\321\237\330", - "\217k\221w\342p\321\356t\257\351subs\206tu\237(\203c\226\220c\202#\322\200p\222\347n\233" -#endif - }; +/* Pawn compiler - Error message strings (plain and compressed formats) + * + * Copyright (c) ITB CompuPhase, 2000-2006 + * + * This software is provided "as-is", without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Version: $Id$ + */ + +SC_FUNC int strexpand(char *dest, unsigned char *source, int maxlen, unsigned char pairtable[128][2]); + +#ifndef SCPACK +# define SCPACK +# define SCPACK_PUSH +#endif + +#define SCPACK_TABLE errstr_table +/*-*SCPACK start of pair table, do not change or remove this line */ +unsigned char errstr_table[][2] = { + {101,32}, {116,32}, {111,110}, {105,110}, {115,32}, {97,114}, {100,32}, {116,105}, {37,115}, {101,114}, {101,110}, {97,108}, {135,130}, {110,111}, {34,136}, {142,34}, + {117,110}, {114,101}, {111,114}, {97,110}, {121,32}, {115,116}, {100,101}, {115,105}, {97,116}, {141,129}, {32,143}, {109,98}, {109,138}, {41,10}, {101,134}, {140,32}, + {116,104}, {98,108}, {144,99}, {102,162}, {114,97}, {111,108}, {117,115}, {146,32}, {118,139}, {97,32}, {115,121}, {170,155}, {171,165}, {103,32}, {137,32}, {103,117}, + {101,120}, {175,156}, {133,164}, {133,177}, {102,131}, {105,134}, {115,151}, {97,161}, {99,104}, {163,159}, {168,181}, {111,102}, {105,132}, {115,10}, {131,186}, {101,100}, + {166,129}, {101,132}, {172,154}, {109,192}, {98,128}, {99,130}, {118,133}, {99,147}, {187,32}, {105,183}, {198,201}, {104,97}, {109,97}, {116,111}, {112,145}, {178,148}, + {199,153}, {150,180}, {116,97}, {109,101}, {99,116}, {179,129}, {130,32}, {133,97}, {149,152}, {44,32}, {102,105}, {118,128}, {154,10}, {101,10}, {109,152}, {194,157}, + {110,32}, {40,223}, {100,105}, {119,105}, {117,108}, {99,111}, {97,115}, {202,128}, {136,10}, {197,149}, {34,32}, {139,32}, {151,122}, {98,101}, {108,111}, {111,112}, + {108,128}, {163,140}, {102,146}, {131,32}, {147,32}, {160,32}, {210,173}, {131,173}, {222,184}, {195,196}, {203,219}, {58,220}, {100,111}, {109,112}, {160,128} +}; +/*-*SCPACK end of pair table, do not change or remove this line */ + +static char *errmsg[] = { +#ifdef SCPACK +/*001*/ "expected token: \"%s\", but found \"%s\"\n", +/*002*/ "only a single statement (or expression) can follow each \"case\"\n", +/*003*/ "declaration of a local variable must appear in a compound block\n", +/*004*/ "function \"%s\" is not implemented\n", +/*005*/ "function may not have arguments\n", +/*006*/ "must be assigned to an array\n", +/*007*/ "operator cannot be redefined\n", +/*008*/ "must be a constant expression; assumed zero\n", +/*009*/ "invalid array size (negative, zero or out of bounds)\n", +/*010*/ "invalid function or declaration\n", +/*011*/ "invalid outside functions\n", +/*012*/ "invalid function call, not a valid address\n", +/*013*/ "no entry point (no public functions)\n", +/*014*/ "invalid statement; not in switch\n", +/*015*/ "\"default\" case must be the last case in switch statement\n", +/*016*/ "multiple defaults in \"switch\"\n", +/*017*/ "undefined symbol \"%s\"\n", +/*018*/ "initialization data exceeds declared size\n", +/*019*/ "not a label: \"%s\"\n", +/*020*/ "invalid symbol name \"%s\"\n", +/*021*/ "symbol already defined: \"%s\"\n", +/*022*/ "must be lvalue (non-constant)\n", +/*023*/ "array assignment must be simple assignment\n", +/*024*/ "\"break\" or \"continue\" is out of context\n", +/*025*/ "function heading differs from prototype\n", +/*026*/ "no matching \"#if...\"\n", +/*027*/ "invalid character constant\n", +/*028*/ "invalid subscript (not an array or too many subscripts): \"%s\"\n", +/*029*/ "invalid expression, assumed zero\n", +/*030*/ "compound statement not closed at the end of file (started at line %d)\n", +/*031*/ "unknown directive\n", +/*032*/ "array index out of bounds (variable \"%s\")\n", +/*033*/ "array must be indexed (variable \"%s\")\n", +/*034*/ "argument does not have a default value (argument %d)\n", +/*035*/ "argument type mismatch (argument %d)\n", +/*036*/ "empty statement\n", +/*037*/ "invalid string (possibly non-terminated string)\n", +/*038*/ "extra characters on line\n", +/*039*/ "constant symbol has no size\n", +/*040*/ "duplicate \"case\" label (value %d)\n", +/*041*/ "invalid ellipsis, array size is not known\n", +/*042*/ "invalid combination of class specifiers\n", +/*043*/ "character constant exceeds range for packed string\n", +/*044*/ "positional parameters must precede all named parameters\n", +/*045*/ "too many function arguments\n", +/*046*/ "unknown array size (variable \"%s\")\n", +/*047*/ "array sizes do not match, or destination array is too small\n", +/*048*/ "array (s do not match\n", +/*049*/ "invalid line continuation\n", +/*050*/ "invalid range\n", +/*051*/ "invalid subscript, use \"[ ]\" operators on major dimensions\n", +/*052*/ "multi-dimensional arrays must be fully initialized\n", +/*053*/ "exceeding maximum number of dimensions\n", +/*054*/ "unmatched closing brace (\"}\")\n", +/*055*/ "start of function body without function header\n", +/*056*/ "arrays, local variables and function arguments cannot be public (variable \"%s\")\n", +/*057*/ "unfinished expression before compiler directive\n", +/*058*/ "duplicate argument; same argument is passed twice\n", +/*059*/ "function argument may not have a default value (variable \"%s\")\n", +/*060*/ "multiple \"#else\" directives between \"#if ... #endif\"\n", +/*061*/ "\"#elseif\" directive follows an \"#else\" directive\n", +/*062*/ "number of operands does not fit the operator\n", +/*063*/ "function result tag of operator \"%s\" must be \"%s\"\n", +/*064*/ "cannot change predefined operators\n", +/*065*/ "function argument may only have a single tag (argument %d)\n", +/*066*/ "function argument may not be a reference argument or an array (argument \"%s\")\n", +/*067*/ "variable cannot be both a reference and an array (variable \"%s\")\n", +/*068*/ "invalid rational number precision in #pragma\n", +/*069*/ "rational number format already defined\n", +/*070*/ "rational number support was not enabled\n", +/*071*/ "user-defined operator must be declared before use (function \"%s\")\n", +/*072*/ "\"sizeof\" operator is invalid on \"function\" symbols\n", +/*073*/ "function argument must be an array (argument \"%s\")\n", +/*074*/ "#define pattern must start with an alphabetic character\n", +/*075*/ "input line too long (after substitutions)\n", +/*076*/ "syntax error in the expression, or invalid function call\n", +/*077*/ "malformed UTF-8 encoding, or corrupted file: %s\n", +/*078*/ "function uses both \"return\" and \"return \"\n", +/*079*/ "inconsistent return types (array & non-array)\n", +/*080*/ "unknown symbol, or not a constant symbol (symbol \"%s\")\n", +/*081*/ "cannot take a tag as a default value for an indexed array parameter (symbol \"%s\")\n", +/*082*/ "user-defined operators and native functions may not have states\n", +/*083*/ "a function or variable may only belong to a single automaton (symbol \"%s\")\n", +/*084*/ "state conflict: one of the states is already assigned to another implementation (symbol \"%s\")\n", +/*085*/ "no states are defined for symbol \"%s\"\n", +/*086*/ "unknown automaton \"%s\"\n", +/*087*/ "unknown state \"%s\" for automaton \"%s\"\n", +/*088*/ "public variables and local variables may not have states (symbol \"%s\")\n", +/*089*/ "state variables may not be initialized (symbol \"%s\")\n", +/*090*/ "public functions may not return arrays (symbol \"%s\")\n", +/*091*/ "ambiguous constant; tag override is required (symbol \"%s\")\n", +/*092*/ "number of arguments does not match definition\n", +/*093*/ "expected tag name identifier\n", +/*094*/ "function enumeration requires unique tag\n", +/*095*/ "cannot have required parameters after optional parameters\n", +/*096*/ "could not find member \"%s\" in struct \"%s\"\n", +/*097*/ "symbol \"%s\" does not have a matching type\n", +/*098*/ "type \"%s\" should be \"%s\" in new-style declarations\n", +/*099*/ "destructors cannot return values\n", +/*100*/ "function prototypes do not match\n", +/*101*/ "specify either all dimensions or only the last dimension\n", +/*102*/ "cannot find %s %s\n", +/*103*/ "%s was already defined on this %s\n", +/*104*/ "cannot find any methods for %s\n", +/*105*/ "cannot find method %s.%s\n", +/*106*/ "cannot call methods on an array\n", +/*107*/ "cannot call methods on a function\n", +/*108*/ "method must have a first argument compatible with the %s type (%s)\n", +/*109*/ "%s name must start with an uppercase letter\n", +/*110*/ "%s has already been defined (previously seen as %s)\n", +/*111*/ "expected identifier - did you forget a type?\n", +/*112*/ "constructor function must return tag %s\n", +/*113*/ "cannot define constructor for \"%s\"; already exists as a %s\n", +/*114*/ "destructor must have the same name as %s \"%s\"\n", +/*115*/ "delete cannot be used with %s\n", +/*116*/ "no methodmap or class was found for %s\n", +/*117*/ "no destructor was found for %s %s\n", +/*118*/ "destructors must be native functions\n", +/*119*/ "destructors cannot have extra arguments\n", +#else + "\260pe\324\236\315k\212:\232\331bu\201fo\220\206\217\012", + "\202l\224\251s\203g\360\330e\234\201(\247\260\316\266\202) \307 f\245\356w ea\270 \042c\346e\042\012", + "\226cl\327\237\310\251\356c\353\347\303appe\205 \363\251\345\375o\220\206\241ock\012", + "\361\232 \274\231i\375le\234t\277\012", + "\271\314\224\231\372\263t\275", + "\371a\266gn\236\315 \364\262y\012", + "\357\211\230\247\320\304\221\321\277\012", + "\371\251\351\223\201\260\316\266\202; \346sum\236z\211o\012", + "\276\317\354\200(nega\207ve\331z\211o \247ou\201\310bo\220ds\235", + "\276\271\247\226cl\327\214\012", + "\276out\227d\200\361\275", + "\276\271c\213l\331\231\251\272add\221s\275", + "\215 \212tr\224po\203\201(\215 pu\241ic \361s\235", + "\276\330e\234t; \231\363s\343t\270\012", + "\042\226fa\344t\352c\346\200\371\376l\346\201c\346\200\363s\343t\270 \330e\234t\012", + "m\344\207p\360\226fa\344t\204\363\042s\343t\270\042\012", + "\220\321\236\302\012", + "\203i\207\213iza\237d\230\251\260ce\277\204\226cl\205\236\354\335", + "\231\251la\355l\373", + "\276\254 nam\200\217\012", + "\254 \213\221ad\224\321\277\373", + "\371l\250u\200(n\202-\351\223t\235", + "\317a\266gn\234\201\371\227\375\360a\266gn\234t\012", + "\042b\221ak\352\247\042\305t\203ue\352\274ou\201\310\305t\260t\012", + "\271head\367\342ff\211\204from pro\315typ\335", + "\215 \370\367\042#if...\042\012", + "\276\270\327\324\256\351\223t\012", + "\276subscrip\201(\231\364\317\247\315o m\223\224subscripts)\373", + "\276\260\316\266\202\331\346sum\236z\211o\012", + "\345\375o\220\206\330e\234\201\231c\356s\236a\201\376\212\206\310\332\360(\225\205t\236a\201l\203\200%d\235", + "\220k\215w\340\342\221c\207v\335", + "\317\203\226x ou\201\310bo\220d\204(\347\217\235", + "\317\371\203\226x\236(\347\217\235", + "\325\374\301\231\372\251\226fa\344\201\250u\200(\325%d\235", + "\325typ\200mis\370 (\325%d\235", + "e\375t\224\330e\234t\012", + "\276\225r\367(po\266\241\224n\202-t\211m\203\230\236\225r\203g\235", + "\260t\244 \270\327\324\211\204\326l\203\335", + "\351\223\201\254 \313\204\215 \354\335", + "duplic\230\200\042c\346e\352la\355l (\250u\200%d\235", + "\276ellip\227s\331\317\354\200\274\231k\215wn\012", + "\276\345\233\203a\237\310cl\346\204speci\332\211\275", + "\270\327\324\256\351\223\201\260ce\277\204r\223g\200f\247pack\236\225r\203g\012", + "po\227\214\353p\327\323t\211\204\303\316c\277\200\213l nam\236p\327\323t\211\275", + "\315o m\223\224\271\263t\275", + "\220k\215w\340\317\354\200(\347\217\235", + "\317\354\301\374 \231\370\331\247\226\225\203a\237\317\274\315o sm\213l\012", + "\317(\204\374 \231\370\012", + "\276l\203\200\305t\203ua\214\012", + "\276r\223g\335", + "\276subscript\331\246\200\042[ ]\352\357\211\230\222\204\326\314j\247\342\234\227\202\275", + "m\344\207-\342\234\227\202\353\262y\204\371f\344l\224\203i\207\213iz\277\012", + "\260ce\277\367\314ximum nu\233\256\310\342\234\227\202\275", + "\220\370\236c\356s\367b\244c\200(\042}\042\235", + "\225\205\201\310\271bod\224\343\240ou\201\271head\211\012", + "\262ys\331\356c\353\312\301\223\206\271\263t\204\320\304pu\241ic (\347\217\235", + "\220\264ish\236\260\316\266\326\355\362\200\345\375il\256\342\221c\207v\335", + "duplic\230\200\263t; sam\200\325\274p\346s\236t\343c\335", + "\271\325\314\224\231\372\251\226fa\344\201\250u\200(\347\217\235", + "m\344\207p\360\042#else\352\342\221c\207v\301\355twe\212 \042#if ... #\212\342f\042\012", + "\042#elseif\352\342\221c\207\333f\245\356w\204\364\042#else\352\342\221c\207v\335", + "nu\233\256\310\357\211\223d\204\374\301\231\332\201\376\357\211\230\222\012", + "\271\221s\344\201\366\310\357\211\230\222\232 \371\217\012", + "\320\270\223g\200\316\321\236\357\211\230\222\275", + "\271\325\314\224\202l\224\372\251s\203g\360\366(\325%d\235", + "\271\325\314\224\231\304\251\221f\211\212c\200\325\247\364\317(\325\217\235", + "\347\320\304bo\365\251\221f\211\212c\200\223\206\364\317(\347\217\235", + "\276\244\214\353nu\233\256\316ci\227\326\363#p\244g\314\012", + "\244\214\353nu\233\256\362\314\201\213\221ad\224\321\277\012", + "\244\214\353nu\233\256supp\222\201wa\204\231\212\267\277\012", + "\246\211-\321\236\357\211\230\247\371\226cl\205\236\355\362\200\246\200(\361\232\235", + "\042\354e\273\352\357\211\230\247\274\276\326\042\361\352\254\275", + "\271\325\371\364\317(\325\217\235", + "#\321\200p\230t\211\340\303\225\205\201\343\365\364\213p\313\355\207c \270\327\324\211\012", + "\203pu\201l\203\200\315o l\202\255(aft\256subs\207tu\214s\235", + "\252n\322x \211r\247\363\376\260\316\266\202\331\247\276\271c\213l\012", + "m\213\362m\236UTF-8 \212\345d\203g\331\247c\222rupt\236\332le: \350", + "\271\246\301bo\365\042\221turn\352\223\206\042\221tur\340<\250ue>\042\012", + "\203\305\227\225\212\201\221tur\340typ\301(\317& n\202-\262y\235", + "\220k\215w\340\254\331\247\231\251\351\223\201\254 \341", + "\320\322k\200\251\366a\204\251\226fa\344\201\250u\200f\247\364\203\226x\236\317p\327\323t\256\341", + "\246\211-\321\236\357\211\230\222\204\223\206na\207\333\361\204\314\224\231\372\330e\275", + "\251\271\247\347\314\224\202l\224\355l\202\255\315 \251s\203g\360au\315\336\326\341", + "\330\200\305fli\324: \202\200\310\376\330\301\274\213\221ad\224a\266gn\236\315 a\215\240\256i\375le\234\322\237\341", + "\215 \330\301\205\200\321\236f\247\302\012", + "\220k\215w\340au\315\336\202\334", + "\220k\215w\340\330\200\217 f\247au\315\336\202\334", + "pu\241ic \312\301\223\206\356c\353\312\301\314\224\231\372\330\301\341", + "\330\200\312\301\314\224\231\304\203i\207\213iz\236\341", + "pu\241ic \361\204\314\224\231\221tur\340\262y\204\341", + "a\233i\257ou\204\351\223t; \366ov\211rid\200\274\221qui\221\206\341", + "nu\233\256\310\263t\204\374\301\231\370 \321i\214\012", + "\260pe\324\236\366nam\200id\212\207\332\211\012", + "\271\212um\211a\237\221qui\221\204\220iqu\200\322g\012", + "\320\372\221qui\221\206p\327\323t\211\204aft\256\357\214\353p\327\323t\211\275", + "\345\344\206\231\264\206\323\233\211\232 \363\225ruc\201\217\012", + "\302 \374\301\231\372\251\370\367typ\335", + "typ\200\217 sho\344\206\304\217 \363new-\225y\360\226cl\327\214\275", + "\226\225ru\324\222\204\320\221tur\340\250ue\275", + "\271pro\315typ\301\374 \231\370\012", + "specif\224ei\240\256\213l \342\234\227\202\204\247\202l\224\376l\346\201\342\234\227\202\012", + "\320\264\206%\204\350", + "%\204wa\204\213\221ad\224\321\236\326\240\274\350", + "\320\264\206\223\224\323\240od\204f\247\350", + "\320\264\206\323\240o\206\210.\350", + "\320c\213l \323\240od\204\326\364\262y\012", + "\320c\213l \323\240od\204\326\251\361\012", + "\323\240o\206\303\372\251\332rs\201\325\345\375a\207\241\200\343\365\376%\204typ\200(\210\235", + "%\204nam\200\303\225\205\201\343\365\364upp\211c\346\200lett\211\012", + "%\204\313\204\213\221ad\224\355\212 \321\236(\316vio\246l\224se\212 a\204\210\235", + "\260pe\324\236id\212\207\332\256- d\265you \362ge\201\251type?\012", + "\351ru\324\247\271\303\221tur\340\366\350", + "\320\321\200\351ru\324\247\362\232; \213\221ad\224\260i\225\204a\204\251\350", + "\226\225ru\324\247\303\372\376sam\200nam\200a\204%\204\217\012", + "\226let\200\320\304\246\236\343\365\350", + "\215 \323\240od\314p \247cl\346\204wa\204fo\220\206f\247\350", + "\215 \226\225ru\324\247wa\204fo\220\206f\247%\204\350", + "\226\225ru\324\222\204\371na\207\333\361\275", + "\226\225ru\324\222\204\320\372\260t\244 \263t\275" +#endif + }; + +static char *fatalmsg[] = { +#ifdef SCPACK +/*120*/ "cannot read from file: \"%s\"\n", +/*121*/ "cannot write to file: \"%s\"\n", +/*122*/ "table overflow: \"%s\"\n", + /* table can be: loop table + * literal table + * staging buffer + * option table (response file) + * peephole optimizer table + */ +/*123*/ "insufficient memory\n", +/*124*/ "invalid assembler instruction \"%s\"\n", +/*125*/ "numeric overflow, exceeding capacity\n", +/*126*/ "compiled script exceeds the maximum memory size (%ld bytes)\n", +/*127*/ "too many error messages on one line\n", +/*128*/ "codepage mapping file not found\n", +/*129*/ "invalid path: \"%s\"\n", +/*130*/ "assertion failed: %s\n", +/*131*/ "user error: %s\n", +#else + "\320\221a\206from \332le\373", + "\320writ\200\315 \332le\373", + "t\267\200ov\211f\356w\373", + "\203suf\332ci\212\201\323m\222y\012", + "\276\346se\233l\256\203\225ruc\214\334", + "num\211ic ov\211f\356w\331\260ce\277\367capacity\012", + "\345\375il\236scrip\201\260ce\277\204\376\314ximum \323m\222\224\354\200(%l\206bytes\235", + "\315o m\223\224\211r\247\323ssag\301\326\202\200l\203\335", + "\345\226pag\200\314pp\367\332\360\231fo\220d\012", + "\276p\230h\373", + "\346s\211\237fail\277: \350", + "\246\256\211r\222: \350" +#endif + }; + +static char *warnmsg[] = { +#ifdef SCPACK +/*200*/ "symbol \"%s\" is truncated to %d characters\n", +/*201*/ "redefinition of constant/macro (symbol \"%s\")\n", +/*202*/ "number of arguments does not match definition\n", +/*203*/ "symbol is never used: \"%s\"\n", +/*204*/ "symbol is assigned a value that is never used: \"%s\"\n", +/*205*/ "redundant code: constant expression is zero\n", +/*206*/ "redundant test: constant expression is non-zero\n", +/*207*/ "unknown #pragma\n", +/*208*/ "function with tag result used before definition, forcing reparse\n", +/*209*/ "function \"%s\" should return a value\n", +/*210*/ "possible use of symbol before initialization: \"%s\"\n", +/*211*/ "possibly unintended assignment\n", +/*212*/ "possibly unintended bitwise operation\n", +/*213*/ "tag mismatch\n", +/*214*/ "possibly a \"const\" array argument was intended: \"%s\"\n", +/*215*/ "expression has no effect\n", +/*216*/ "nested comment\n", +/*217*/ "loose indentation\n", +/*218*/ "old style prototypes used with optional semicolumns\n", +/*219*/ "local variable \"%s\" shadows a variable at a preceding level\n", +/*220*/ "expression with tag override must appear between parentheses\n", +/*221*/ "label name \"%s\" shadows tag name\n", +/*222*/ "number of digits exceeds rational number precision\n", +/*223*/ "redundant \"sizeof\": argument size is always 1 (symbol \"%s\")\n", +/*224*/ "indeterminate array size in \"sizeof\" expression (symbol \"%s\")\n", +/*225*/ "unreachable code\n", +/*226*/ "a variable is assigned to itself (symbol \"%s\")\n", +/*227*/ "more initializers than enum fields\n", +/*228*/ "length of initializer exceeds size of the enum field\n", +/*229*/ "index tag mismatch (symbol \"%s\")\n", +/*230*/ "no implementation for state \"%s\" in function \"%s\", no fall-back\n", +/*231*/ "state specification on forward declaration is ignored\n", +/*232*/ "output file is written, but with compact encoding disabled\n", +/*233*/ "state variable \"%s\" shadows a global variable\n", +/*234*/ "symbol \"%s\" is marked as deprecated: %s\n", +/*235*/ "public function lacks forward declaration (symbol \"%s\")\n", +/*236*/ "unknown parameter in substitution (incorrect #define pattern)\n" +#else + "\302 \274tr\242\230\236\315 %\206\270\327\324\211\275", + "\221\321i\237\310\351\223t/\314cro \341", + "nu\233\256\310\263t\204\374\301\231\370 \321i\214\012", + "\254 \274nev\256\246\277\373", + "\254 \274a\266gn\236\251\250u\200\240a\201\274nev\256\246\277\373", + "\221d\220d\223\201\345\226: \351\223\201\260\316\266\326\274z\211o\012", + "\221d\220d\223\201te\225: \351\223\201\260\316\266\326\274n\202-z\211o\012", + "\220k\215w\340#p\244g\314\012", + "\271\343\365\366\221s\344\201\246\236\355\362\200\321i\214\331\362c\367\221p\205s\335", + "\361\232 sho\344\206\221tur\340\251\250u\335", + "po\266\241\200\246\200\310\254 \355\362\200\203i\207\213iza\214\373", + "po\266\241\224\220\203t\212\226\206a\266gn\234t\012", + "po\266\241\224\220\203t\212\226\206bit\343s\200\357\211a\214\012", + "\366mis\370\012", + "po\266\241\224\251\042\351\352\317\325wa\204\203t\212\226d\373", + "\260\316\266\326\313\204\215 effe\324\012", + "ne\225\236\345m\234t\012", + "\356os\200\203d\212\322\214\012", + "\245\206\225y\360pro\315typ\301\246\236\343\365\357\214\353semic\245umn\275", + "\356c\353\347\217 s\313\374w\204\251\347a\201\251\316c\277\367level\012", + "\260\316\266\326\343\365\366ov\211rid\200\303appe\205 \355twe\212 p\205\212\240ese\275", + "la\355l nam\200\217 s\313\374w\204\366na\323\012", + "nu\233\256\310\342git\204\260ce\277\204\244\214\353nu\233\256\316ci\227\202\012", + "\221d\220d\223\201\042\354e\273\042: \325\354\200\274\213way\2041 \341", + "\203\226t\211m\203\230\200\317\354\200\363\042\354e\273\352\260\316\266\326\341", + "\220\221a\270\267\200\345\226\012", + "\251\347\274a\266gn\236\315 itself \341", + "m\222\200\203i\207\213iz\211\204\240\364\212um \332eld\275", + "l\212g\365\310\203i\207\213iz\256\260ce\277\204\354\200\310\376\212um \332eld\012", + "\203\226x \366mis\370 \341", + "\215 i\375le\234\322\237f\247\330\200\217 \363\361\232\331\215 f\213l-back\012", + "\330\200speci\332ca\237\326\362w\205\206\226cl\327\237\274ig\215\221d\012", + "outpu\201\332\360\274writt\212\331bu\201\343\365\345\375ac\201\212\345d\367\342s\267\277\012", + "\330\200\347\217 s\313\374w\204\251g\356b\353\312\335", + "\302 \274m\205k\236a\204\226\316c\230\277: \350", + "pu\241ic \271lack\204\362w\205\206\226cl\327\237\341", + "\220k\215w\340p\327\323t\256\363subs\207tu\237(\203c\222\221c\201#\321\200p\230t\211n\235" +#endif + }; + +#ifdef SCPACK_PUSH +# undef SCPACK +#endif diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index 7b20ab1b..85c7c026 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -1,3 +1,4 @@ +/* vim: set ts=8 sts=2 sw=2 tw=99 et: */ #include #include #include @@ -10,6 +11,8 @@ funcenum_t *firstenum = NULL; funcenum_t *lastenum = NULL; pstruct_t *firststruct = NULL; pstruct_t *laststruct = NULL; +methodmap_t *methodmap_first = NULL; +methodmap_t *methodmap_last = NULL; structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member) { @@ -345,20 +348,20 @@ void _stack_genusage(memuse_list_t *stack, int dofree) while (cur) { if (cur->type == MEMUSE_DYNAMIC) - { + { /* no idea yet */ assert(0); - } else { + } else { modstk(cur->size * sizeof(cell)); - } - if (dofree) - { + } + if (dofree) + { tmp = cur->prev; free(cur); cur = tmp; - } else { + } else { cur = cur->prev; - } + } } if (dofree) { @@ -411,6 +414,13 @@ void popstacklist(int codegen) { _stack_genusage(stackusage, 1); assert(stackusage->head==NULL); + } else { + memuse_t *use = stackusage->head; + while (use) { + memuse_t *temp = use->prev; + free(use); + use = temp; + } } oldlist = stackusage->prev; @@ -427,3 +437,141 @@ void resetheaplist() { _reset_memlist(&heapusage); } + +void methodmap_add(methodmap_t *map) +{ + if (!methodmap_first) { + methodmap_first = map; + methodmap_last = map; + } else { + methodmap_last->next = map; + methodmap_last = map; + } +} + +methodmap_t *methodmap_find_by_tag(int tag) +{ + methodmap_t *ptr = methodmap_first; + for (; ptr; ptr = ptr->next) { + if (ptr->tag == tag) + return ptr; + } + return NULL; +} + +methodmap_t *methodmap_find_by_name(const char *name) +{ + int tag = pc_findtag(name); + if (tag == -1) + return NULL; + return methodmap_find_by_tag(tag); +} + +methodmap_method_t *methodmap_find_method(methodmap_t *map, const char *name) +{ + size_t i; + for (i = 0; i < map->nummethods; i++) { + if (strcmp(map->methods[i]->name, name) == 0) + return map->methods[i]; + } + if (map->parent) + return methodmap_find_method(map->parent, name); + return NULL; +} + +void methodmaps_free() +{ + methodmap_t *ptr = methodmap_first; + while (ptr) { + methodmap_t *next = ptr->next; + for (size_t i = 0; i < ptr->nummethods; i++) + free(ptr->methods[i]); + free(ptr->methods); + free(ptr); + ptr = next; + } + methodmap_first = NULL; + methodmap_last = NULL; +} + +LayoutSpec deduce_layout_spec_by_tag(int tag) +{ + symbol *sym; + const char *name; + methodmap_t *map; + if ((map = methodmap_find_by_tag(tag)) != NULL) + return map->spec; + if (tag & FUNCTAG) + return Layout_FuncTag; + + name = pc_tagname(tag); + if (pstructs_find(name)) + return Layout_PawnStruct; + if ((sym = findglb(name, sGLOBAL)) != NULL) + return Layout_Enum; + + return Layout_None; +} + +LayoutSpec deduce_layout_spec_by_name(const char *name) +{ + symbol *sym; + methodmap_t *map; + int tag = pc_findtag(name); + if (tag != -1 && (tag & FUNCTAG)) + return Layout_FuncTag; + if (pstructs_find(name)) + return Layout_PawnStruct; + if ((map = methodmap_find_by_name(name)) != NULL) + return map->spec; + if ((sym = findglb(name, sGLOBAL)) != NULL) + return Layout_Enum; + + return Layout_None; +} + +const char *layout_spec_name(LayoutSpec spec) +{ + switch (spec) { + case Layout_None: + return ""; + case Layout_Enum: + return "enum"; + case Layout_FuncTag: + return "functag"; + case Layout_PawnStruct: + return "deprecated-struct"; + case Layout_MethodMap: + return "methodmap"; + case Layout_Class: + return "class"; + } + return ""; +} + +int can_redef_layout_spec(LayoutSpec def1, LayoutSpec def2) +{ + // Normalize the ordering, since these checks are symmetrical. + if (def1 > def2) { + LayoutSpec temp = def2; + def2 = def1; + def1 = temp; + } + + switch (def1) { + case Layout_None: + return TRUE; + case Layout_Enum: + if (def2 == Layout_Enum || def2 == Layout_FuncTag) + return TRUE; + return def2 == Layout_MethodMap; + case Layout_FuncTag: + return def2 == Layout_Enum || def2 == Layout_FuncTag; + case Layout_PawnStruct: + case Layout_MethodMap: + return FALSE; + case Layout_Class: + return FALSE; + } + return FALSE; +} diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index 1aecdc09..15e35f90 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -1,3 +1,4 @@ +/* vim: set sts=2 ts=8 sw=2 tw=99 et: */ #ifndef _INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_ #define _INCLUDE_SOURCEPAWN_COMPILER_TRACKER_H_ @@ -66,6 +67,42 @@ typedef struct pstruct_s struct pstruct_s *next; } pstruct_t; +// The ordering of these definitions should be preserved for +// can_redef_layout_spec(). +typedef enum LayoutSpec_t +{ + Layout_None, + Layout_Enum, + Layout_FuncTag, + Layout_PawnStruct, + Layout_MethodMap, + Layout_Class +} LayoutSpec; + +// The method name buffer is larger since we can include our parent class's +// name, a "." to separate it, and a "~" for constructors. +#define METHOD_NAMEMAX sNAMEMAX * 2 + 2 + +typedef struct methodmap_method_s +{ + char name[METHOD_NAMEMAX + 1]; + symbol *target; +} methodmap_method_t; + +typedef struct methodmap_s +{ + struct methodmap_s *next; + struct methodmap_s *parent; + int tag; + LayoutSpec spec; + char name[sNAMEMAX+1]; + methodmap_method_t **methods; + size_t nummethods; + + // Shortcut. + methodmap_method_t *dtor; +} methodmap_t; + /** * Pawn Structs */ @@ -83,6 +120,14 @@ funcenum_t *funcenums_add(const char *name); funcenum_t *funcenums_find_byval(int value); functag_t *functags_add(funcenum_t *en, functag_t *src); +/** + * Given a name or tag, find any extra weirdness it has associated with it. + */ +LayoutSpec deduce_layout_spec_by_tag(int tag); +LayoutSpec deduce_layout_spec_by_name(const char *name); +const char *layout_spec_name(LayoutSpec spec); +int can_redef_layout_spec(LayoutSpec olddef, LayoutSpec newdef); + /** * Heap functions */ @@ -111,6 +156,15 @@ void genheapfree(int stop_id); void resetstacklist(); void resetheaplist(); +/** + * Method maps. + */ +void methodmap_add(methodmap_t *map); +methodmap_t *methodmap_find_by_tag(int tag); +methodmap_t *methodmap_find_by_name(const char *name); +methodmap_method_t *methodmap_find_method(methodmap_t *map, const char *name); +void methodmaps_free(); + extern memuse_list_t *heapusage; extern memuse_list_t *stackusage; diff --git a/sourcepawn/compiler/tests/fail-array-on-implicit-this.sp b/sourcepawn/compiler/tests/fail-array-on-implicit-this.sp new file mode 100644 index 00000000..a23db3b1 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-array-on-implicit-this.sp @@ -0,0 +1,9 @@ +native CloseHandle(Handle:this[]); + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ +} diff --git a/sourcepawn/compiler/tests/fail-array-on-implicit-this.txt b/sourcepawn/compiler/tests/fail-array-on-implicit-this.txt new file mode 100644 index 00000000..aedab634 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-array-on-implicit-this.txt @@ -0,0 +1 @@ +method must have a first argument compatible with the methodmap type (Handle) diff --git a/sourcepawn/compiler/tests/fail-ctor-bad-return-type.sp b/sourcepawn/compiler/tests/fail-ctor-bad-return-type.sp new file mode 100644 index 00000000..ee9ad489 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-ctor-bad-return-type.sp @@ -0,0 +1,13 @@ +native Float:CreateHandle(count); +native CloseHandle(Handle:handle); + +methodmap Handle { + public Handle() = CreateHandle; + public Close() = CloseHandle; +}; + +public main() { + new Handle:handle = Handle(3); + handle.Close(); +} + diff --git a/sourcepawn/compiler/tests/fail-ctor-bad-return-type.txt b/sourcepawn/compiler/tests/fail-ctor-bad-return-type.txt new file mode 100644 index 00000000..59bc1840 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-ctor-bad-return-type.txt @@ -0,0 +1 @@ +constructor function must return tag Handle diff --git a/sourcepawn/compiler/tests/fail-dtor-extra-args.sp b/sourcepawn/compiler/tests/fail-dtor-extra-args.sp new file mode 100644 index 00000000..385ee301 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-dtor-extra-args.sp @@ -0,0 +1,8 @@ +native Q(X:this, a); + +methodmap X { + public ~X() = Q; +} + +public main() { +} diff --git a/sourcepawn/compiler/tests/fail-dtor-extra-args.txt b/sourcepawn/compiler/tests/fail-dtor-extra-args.txt new file mode 100644 index 00000000..2f86263c --- /dev/null +++ b/sourcepawn/compiler/tests/fail-dtor-extra-args.txt @@ -0,0 +1 @@ +destructors cannot have extra arguments diff --git a/sourcepawn/compiler/tests/fail-dtor-non-native.sp b/sourcepawn/compiler/tests/fail-dtor-non-native.sp new file mode 100644 index 00000000..33de1d20 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-dtor-non-native.sp @@ -0,0 +1,10 @@ +Q(X:this) +{ +} + +methodmap X { + public ~X() = Q; +} + +public main() { +} diff --git a/sourcepawn/compiler/tests/fail-dtor-non-native.txt b/sourcepawn/compiler/tests/fail-dtor-non-native.txt new file mode 100644 index 00000000..43b690c2 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-dtor-non-native.txt @@ -0,0 +1 @@ +destructors must be native functions diff --git a/sourcepawn/compiler/tests/fail-dtor-returns-value.sp b/sourcepawn/compiler/tests/fail-dtor-returns-value.sp new file mode 100644 index 00000000..26632f9c --- /dev/null +++ b/sourcepawn/compiler/tests/fail-dtor-returns-value.sp @@ -0,0 +1,8 @@ +native bool:Q(); + +methodmap X { + public ~X() = Q; +} + +public main() { +} diff --git a/sourcepawn/compiler/tests/fail-dtor-returns-value.txt b/sourcepawn/compiler/tests/fail-dtor-returns-value.txt new file mode 100644 index 00000000..425de1c0 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-dtor-returns-value.txt @@ -0,0 +1 @@ +destructors cannot return values diff --git a/sourcepawn/compiler/tests/fail-duplicate-methods.sp b/sourcepawn/compiler/tests/fail-duplicate-methods.sp new file mode 100644 index 00000000..52f54937 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-duplicate-methods.sp @@ -0,0 +1,8 @@ +native X:Crab(); +methodmap X { + public X() = Crab; + public X() = Crab; +} + +public main() { +} diff --git a/sourcepawn/compiler/tests/fail-duplicate-methods.txt b/sourcepawn/compiler/tests/fail-duplicate-methods.txt new file mode 100644 index 00000000..31daf0de --- /dev/null +++ b/sourcepawn/compiler/tests/fail-duplicate-methods.txt @@ -0,0 +1 @@ +X was already defined on this methodmap diff --git a/sourcepawn/compiler/tests/fail-method-on-array.sp b/sourcepawn/compiler/tests/fail-method-on-array.sp new file mode 100644 index 00000000..39febd3e --- /dev/null +++ b/sourcepawn/compiler/tests/fail-method-on-array.sp @@ -0,0 +1,12 @@ +native CloseHandle(Handle:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ + new Handle:x[2]; + + x.Close(); +} diff --git a/sourcepawn/compiler/tests/fail-method-on-array.txt b/sourcepawn/compiler/tests/fail-method-on-array.txt new file mode 100644 index 00000000..e01ded18 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-method-on-array.txt @@ -0,0 +1 @@ +cannot call methods on an array diff --git a/sourcepawn/compiler/tests/fail-method-on-function.sp b/sourcepawn/compiler/tests/fail-method-on-function.sp new file mode 100644 index 00000000..145199b4 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-method-on-function.sp @@ -0,0 +1,10 @@ +native CloseHandle(Handle:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ + main.Close(); +} diff --git a/sourcepawn/compiler/tests/fail-method-on-function.txt b/sourcepawn/compiler/tests/fail-method-on-function.txt new file mode 100644 index 00000000..47a85b6f --- /dev/null +++ b/sourcepawn/compiler/tests/fail-method-on-function.txt @@ -0,0 +1 @@ +cannot call methods on a function diff --git a/sourcepawn/compiler/tests/fail-mismatch-on-implicit-this.sp b/sourcepawn/compiler/tests/fail-mismatch-on-implicit-this.sp new file mode 100644 index 00000000..46e49834 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-mismatch-on-implicit-this.sp @@ -0,0 +1,9 @@ +native CloseHandle(HandleEgg:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ +} diff --git a/sourcepawn/compiler/tests/fail-mismatch-on-implicit-this.txt b/sourcepawn/compiler/tests/fail-mismatch-on-implicit-this.txt new file mode 100644 index 00000000..aedab634 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-mismatch-on-implicit-this.txt @@ -0,0 +1 @@ +method must have a first argument compatible with the methodmap type (Handle) diff --git a/sourcepawn/compiler/tests/fail-multi-tag-on-implicit-this.sp b/sourcepawn/compiler/tests/fail-multi-tag-on-implicit-this.sp new file mode 100644 index 00000000..5ff84db6 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-multi-tag-on-implicit-this.sp @@ -0,0 +1,9 @@ +native CloseHandle({Handle, Egg}:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ +} diff --git a/sourcepawn/compiler/tests/fail-multi-tag-on-implicit-this.txt b/sourcepawn/compiler/tests/fail-multi-tag-on-implicit-this.txt new file mode 100644 index 00000000..aedab634 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-multi-tag-on-implicit-this.txt @@ -0,0 +1 @@ +method must have a first argument compatible with the methodmap type (Handle) diff --git a/sourcepawn/compiler/tests/fail-no-tag-on-implicit-this.sp b/sourcepawn/compiler/tests/fail-no-tag-on-implicit-this.sp new file mode 100644 index 00000000..df7b09f1 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-no-tag-on-implicit-this.sp @@ -0,0 +1,9 @@ +native CloseHandle(this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ +} diff --git a/sourcepawn/compiler/tests/fail-no-tag-on-implicit-this.txt b/sourcepawn/compiler/tests/fail-no-tag-on-implicit-this.txt new file mode 100644 index 00000000..aedab634 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-no-tag-on-implicit-this.txt @@ -0,0 +1 @@ +method must have a first argument compatible with the methodmap type (Handle) diff --git a/sourcepawn/compiler/tests/fail-ref-on-implicit-this.sp b/sourcepawn/compiler/tests/fail-ref-on-implicit-this.sp new file mode 100644 index 00000000..be718f1f --- /dev/null +++ b/sourcepawn/compiler/tests/fail-ref-on-implicit-this.sp @@ -0,0 +1,9 @@ +native CloseHandle(&Handle:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ +} diff --git a/sourcepawn/compiler/tests/fail-ref-on-implicit-this.txt b/sourcepawn/compiler/tests/fail-ref-on-implicit-this.txt new file mode 100644 index 00000000..aedab634 --- /dev/null +++ b/sourcepawn/compiler/tests/fail-ref-on-implicit-this.txt @@ -0,0 +1 @@ +method must have a first argument compatible with the methodmap type (Handle) diff --git a/sourcepawn/compiler/tests/ok-base-type-as-thistag.sp b/sourcepawn/compiler/tests/ok-base-type-as-thistag.sp new file mode 100644 index 00000000..34dde541 --- /dev/null +++ b/sourcepawn/compiler/tests/ok-base-type-as-thistag.sp @@ -0,0 +1,14 @@ +native CloseHandle(Handle:this); + +methodmap Handle { +}; + +methodmap Crab < Handle { + public Close() = CloseHandle; +}; + +public main() +{ + new Crab:x; + x.Close(); +} diff --git a/sourcepawn/compiler/tests/ok-ctor-dtor.sp b/sourcepawn/compiler/tests/ok-ctor-dtor.sp new file mode 100644 index 00000000..cb5cfbdc --- /dev/null +++ b/sourcepawn/compiler/tests/ok-ctor-dtor.sp @@ -0,0 +1,12 @@ +native Handle:CreateHandle(count); +native CloseHandle(Handle:handle); + +methodmap Handle { + public Handle() = CreateHandle; + public ~Handle() = CloseHandle; +}; + +public main() { + new Handle:handle = Handle(3); + delete handle; +} diff --git a/sourcepawn/compiler/tests/ok-inheritance.sp b/sourcepawn/compiler/tests/ok-inheritance.sp new file mode 100644 index 00000000..62f5989a --- /dev/null +++ b/sourcepawn/compiler/tests/ok-inheritance.sp @@ -0,0 +1,14 @@ +native CloseHandle(Handle:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +methodmap Crab < Handle { +}; + +public main() +{ + new Crab:x; + x.Close(); +} diff --git a/sourcepawn/compiler/tests/ok-method-on-const.sp b/sourcepawn/compiler/tests/ok-method-on-const.sp new file mode 100644 index 00000000..d9c65ecb --- /dev/null +++ b/sourcepawn/compiler/tests/ok-method-on-const.sp @@ -0,0 +1,14 @@ +native CloseHandle(Handle:this); + +enum Handle { + INVALID_HANDLE = 0, +}; + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ + INVALID_HANDLE.Close(); +} diff --git a/sourcepawn/compiler/tests/ok-method-on-constref.sp b/sourcepawn/compiler/tests/ok-method-on-constref.sp new file mode 100644 index 00000000..89d4ced4 --- /dev/null +++ b/sourcepawn/compiler/tests/ok-method-on-constref.sp @@ -0,0 +1,16 @@ +native CloseHandle(Handle:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +f(const &Handle:x) +{ + x.Close() +} + +public main() +{ + new Handle:x; + f(x) +} diff --git a/sourcepawn/compiler/tests/ok-method-on-element.sp b/sourcepawn/compiler/tests/ok-method-on-element.sp new file mode 100644 index 00000000..f72bf12c --- /dev/null +++ b/sourcepawn/compiler/tests/ok-method-on-element.sp @@ -0,0 +1,11 @@ +native CloseHandle(Handle:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +public main() +{ + new Handle:x[2]; + x[1].Close(); +} diff --git a/sourcepawn/compiler/tests/ok-method-on-ref.sp b/sourcepawn/compiler/tests/ok-method-on-ref.sp new file mode 100644 index 00000000..5436cf33 --- /dev/null +++ b/sourcepawn/compiler/tests/ok-method-on-ref.sp @@ -0,0 +1,16 @@ +native CloseHandle(Handle:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +f(&Handle:x) +{ + x.Close() +} + +public main() +{ + new Handle:x; + f(x) +} diff --git a/sourcepawn/compiler/tests/ok-method-on-scalar.sp b/sourcepawn/compiler/tests/ok-method-on-scalar.sp new file mode 100644 index 00000000..62c4f017 --- /dev/null +++ b/sourcepawn/compiler/tests/ok-method-on-scalar.sp @@ -0,0 +1,13 @@ +native CloneHandle(Handle:this); +native CloseHandle(Handle:this); + +methodmap Handle { + public Clone() = CloneHandle; + public Close() = CloseHandle; +}; + +public main() +{ + new Handle:x; + x.Close(); +} diff --git a/sourcepawn/compiler/tests/runtests.py b/sourcepawn/compiler/tests/runtests.py new file mode 100644 index 00000000..58e12fe8 --- /dev/null +++ b/sourcepawn/compiler/tests/runtests.py @@ -0,0 +1,74 @@ +# vim: set ts=4 sw=4 tw=99 et: +import os, sys +import argparse +import subprocess + +def run_tests(args): + testdir = os.path.dirname(os.path.abspath(__file__)) + tests = [] + for filename in os.listdir(testdir): + base, ext = os.path.splitext(filename) + if ext == '.sp': + tests += [base] + + failed = False + + for test in tests: + print('Testing {0}...'.format(test)) + if test.startswith('fail-'): + kind = 'fail' + elif test.startswith('warn-'): + kind = 'warn' + elif test.startswith('ok-'): + kind = 'pass' + + try: + argv = [args.spcomp, os.path.join(testdir, test + '.sp')] + p = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + stdout = stdout.decode('utf-8') + stderr = stderr.decode('utf-8') + + smx_path = test + '.smx' + compiled = os.path.exists(smx_path) + if compiled: + os.unlink(smx_path) + + status = 'ok' + if compiled and kind == 'fail': + status = 'fail' + elif not compiled and kind != 'fail': + status = 'fail' + + if status == 'ok' and kind != 'pass': + with open(os.path.join(testdir, test + '.txt')) as fp: + text = fp.read() + if text not in stdout: + print('Expected to find text in stdout: >>>') + print(text) + print('<<<') + status = 'fail' + + if status == 'fail': + failed = True + print('FAILED! Dumping stdout/stderr:') + print(stdout) + print(stderr) + else: + print('... OK!') + + except Exception as exn: + raise + sys.stderr.write('FAILED! {0}\n'.format(exn.message)) + + if failed: + sys.exit(1) + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('spcomp', type=str, help='Path to spcomp') + args = parser.parse_args() + run_tests(args) + +if __name__ == '__main__': + main() diff --git a/sourcepawn/compiler/tests/warn-bad-upcast.sp b/sourcepawn/compiler/tests/warn-bad-upcast.sp new file mode 100644 index 00000000..f3630c09 --- /dev/null +++ b/sourcepawn/compiler/tests/warn-bad-upcast.sp @@ -0,0 +1,15 @@ +native CloseHandle(Handle:this); + +methodmap Handle { + public Close() = CloseHandle; +}; + +methodmap Crab { +}; + +public main() +{ + new Crab:x; + new Handle:y; + x = y; +} diff --git a/sourcepawn/compiler/tests/warn-bad-upcast.txt b/sourcepawn/compiler/tests/warn-bad-upcast.txt new file mode 100644 index 00000000..bdb238a4 --- /dev/null +++ b/sourcepawn/compiler/tests/warn-bad-upcast.txt @@ -0,0 +1 @@ +tag mismatch