Pol  Revision:cb584c9
parser.cpp
Go to the documentation of this file.
1 
43 #include "parser.h"
44 
45 #include <cctype>
46 #include <cstddef>
47 #include <cstdlib>
48 #include <cstring>
49 #include <mutex>
50 #include <string>
51 #include <unordered_map>
52 
53 #include "../clib/clib.h"
54 #include "../clib/logfacility.h"
55 #include "../clib/passert.h"
56 #include "../clib/rawtypes.h"
57 #include "../clib/strutil.h"
58 #include "../clib/unittest.h"
59 #include "compctx.h"
60 #include "compilercfg.h"
61 #include "fmodule.h"
62 #include "modules.h"
63 #include "objmembers.h"
64 #include "objmethods.h"
65 #include "token.h"
66 #include "tokens.h"
67 #include <format/format.h>
68 
69 namespace Pol
70 {
71 namespace Bscript
72 {
73 static void init_tables();
74 
75 Parser::Parser() : quiet( 0 ), err( PERR_NONE ), contains_tabs( false )
76 {
77  memset( &ext_err, 0, sizeof( ext_err ) );
78  memset( &buffer, 0, sizeof( buffer ) );
79  init_tables();
80 }
81 
82 const char* ParseErrorStr[PERR_NUM_ERRORS] = {"(No Error, or not specified)",
83  "Unexpected ')'",
84  "Missing '('",
85  "Missing ')'",
86  "Bad Token",
87  "Unknown Operator",
88  "Waaah!",
89  "Unterminated String Literal",
90  "Invalid escape sequence in String",
91  "Too Few Arguments",
92  "Too Many Arguments",
93  "Unexpected Comma",
94  "Illegal Construction",
95  "Missing ';'",
96  "Token not legal here",
97  "Procedure calls not allowed here",
98  "Unexpected Semicolon",
99  "Expected 'while'",
100  "Unexpected ']'",
101  "Missing ']'"};
102 char operator_brk[] = "+-/*(),<=>,:;%";
103 
105  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
106  "abcdefghijklmnopqrstuvwxyz"
107  "0123456789"
108  "_"; // $%@& removed 9/17/1998 Syz
109 
110 
111 int allowed_table[8][8] = {
112  /* this token is a(n)... */
113  /* binary unary
114  * TERMINATOR OPERAND OPERATOR OPERATOR LPAREN RPAREN LBRACK RBRACK*/
115  /* Last token was a(n)... */
116  {1, 1, 0, 1, 1, 0, 0, 0}, /* TERMINATOR */
117  {1, 0, 1, 0, 0, 1, 1, 1}, /* OPERAND */
118  {0, 1, 0, 1, 1, 0, 0, 0}, /* BINARY OPERATOR */
119  {0, 1, 0, 0, 1, 0, 0, 0}, /* UNARY OPERATOR */
120  {0, 1, 0, 1, 1, 0, 0, 0}, /* LEFT PARENTHESIS */
121  {1, 0, 1, 0, 0, 1, 0, 1}, /* RIGHT PARENTHESIS */
122  {0, 1, 0, 0, 1, 0, 1, 0}, /* LEFT BRACKET */
123  {1, 0, 1, 0, 0, 1, 1, 1}, /* RIGHT BRACKET */
124  /* Separators are always allowed. Terminators are mostly always allowed. */
125 };
126 /* examples matrix: -- connected denotes unary operator
127 
128 legal:
129 { TT T AB T -AB T ( },
130 { AB T AB + AB ) A[ A] },
131 { * AB *- * ( },
132 { -AB -( },
133 { ( AB (- ( ( },
134 { ) T ) - ) ) )] }
135 { [A . [- [( [[ . }
136 { ] T . ] * . . ]) ][ ][ }
137 
138 illegal:
139 { T b-A T ) T [ T ] },
140 { AB AB AB~ AB ( },
141 { * T * / - ) *[ *] },
142 { b- T -* -- -) -[ -] },
143 { ( T ( * ( ) ([ (] },
144 { ) AB )- ) ( )[ }
145 { [ T [+ [) [] }
146 { ]A ]- ] ( . }
147 
148 */
149 
150 
151 /* operator characters // (and precedence table)
152  ( ) [ ]
153  + - (unary-arithmetic) ! (unary-logical) ~ (unary-boolean)
154  * / %
155  + -
156  < <= > >=
157  == <>
158  & (band ?)
159  ^ (bxor ?)
160  | (bor ?)
161  and
162  or
163  :=
164  ,
165 
166  Problem: How to recognize a unary operator?
167  Proposed solution: If a binary operator would be legal, use it
168  otherwise, it must be a unary operator.
169  Examples: (-5+7)
170  1) grabs '('. now only lparens and operands are legal.
171  2) grabs '-'. Since this is a binary operator (TYP_OPERATOR)
172  by default, this is illegal. Since it is illegal,
173  parseToken() tries the unary operator table, and finds it.
174  ( now, only left parens and operands are legal. )
175  3) gets 5, an operand.
176  Alternative: Pass getToken()a parameter denoting what is legal and
177  let it ignore possibilities that are illegal.
178 
179  See end of file for handling unary operators
180  */
181 
182 /*
183  The precedence table should be split from the operator
184  recognition table, because some operators are words and
185  have to be picked up in the reserved word table.
186  */
187 
188 
190 
191  {"(", TOK_LPAREN, PREC_PAREN, TYP_LEFTPAREN, false, false},
192  {")", TOK_RPAREN, PREC_PAREN, TYP_RIGHTPAREN, false, false},
193  {"[", TOK_LBRACKET, PREC_PAREN, TYP_LEFTBRACKET, false, false},
194  {"]", TOK_RBRACKET, PREC_PAREN, TYP_RIGHTBRACKET, false, false},
195  {"{", TOK_LBRACE, PREC_PAREN, TYP_LEFTBRACE, false, false},
196  {"}", TOK_RBRACE, PREC_PAREN, TYP_RIGHTBRACE, false, false},
197 
198  {".", TOK_MEMBER, PREC_PAREN, TYP_OPERATOR, true, false},
199  {"->", TOK_DICTKEY, PREC_ASSIGN, TYP_RESERVED, false, false},
200 
201  {"*", TOK_MULT, PREC_MULT, TYP_OPERATOR, true, false},
202  {"/", TOK_DIV, PREC_MULT, TYP_OPERATOR, true, false},
203  {"%", TOK_MODULUS, PREC_MULT, TYP_OPERATOR, true, false},
204 
205  {"+", TOK_ADD, PREC_PLUS, TYP_OPERATOR, true, false},
206  {"-", TOK_SUBTRACT, PREC_PLUS, TYP_OPERATOR, true, false},
207 
208  {"+=", TOK_PLUSEQUAL, PREC_ASSIGN, TYP_OPERATOR, false, false},
209  {"-=", TOK_MINUSEQUAL, PREC_ASSIGN, TYP_OPERATOR, false, false},
210  {"*=", TOK_TIMESEQUAL, PREC_ASSIGN, TYP_OPERATOR, false, false},
211  {"/=", TOK_DIVIDEEQUAL, PREC_ASSIGN, TYP_OPERATOR, false, false},
212  {"%=", TOK_MODULUSEQUAL, PREC_ASSIGN, TYP_OPERATOR, false, false},
213 
214  {"<=", TOK_LESSEQ, PREC_LESSTHAN, TYP_OPERATOR, false, false},
215  {"<", TOK_LESSTHAN, PREC_LESSTHAN, TYP_OPERATOR, true, false},
216  {">=", TOK_GREQ, PREC_LESSTHAN, TYP_OPERATOR, false, false},
217  {">", TOK_GRTHAN, PREC_LESSTHAN, TYP_OPERATOR, true, false},
218 
219  {">>", TOK_BSRIGHT, PREC_BSRIGHT, TYP_OPERATOR, false, false},
220  {"<<", TOK_BSLEFT, PREC_BSLEFT, TYP_OPERATOR, false, false},
221  {"&", TOK_BITAND, PREC_BITAND, TYP_OPERATOR, true, false},
222  {"^", TOK_BITXOR, PREC_BITXOR, TYP_OPERATOR, false, false},
223  {"|", TOK_BITOR, PREC_BITOR, TYP_OPERATOR, true, false},
224 
225  {"<>", TOK_NEQ, PREC_EQUALTO, TYP_OPERATOR, false, false},
226  {"!=", TOK_NEQ, PREC_EQUALTO, TYP_OPERATOR, false, false},
227  {"=", TOK_EQUAL1, PREC_EQUALTO, TYP_OPERATOR, true, false}, // deprecated: :=/==
228  {"==", TOK_EQUAL, PREC_EQUALTO, TYP_OPERATOR, false, false},
229 
230  // { "and", TOK_AND, PREC_LOGAND, TYP_OPERATOR, false, false },
231  {"&&", TOK_AND, PREC_LOGAND, TYP_OPERATOR, false, false},
232 
233  // { "or", TOK_OR, PREC_LOGOR, TYP_OPERATOR, false, false },
234  {"||", TOK_OR, PREC_LOGOR, TYP_OPERATOR, false, false},
235 
236  {":=", TOK_ASSIGN, PREC_ASSIGN, TYP_OPERATOR, false, false},
237  {".+", TOK_ADDMEMBER, PREC_ASSIGN, TYP_OPERATOR, false, false},
238  {".-", TOK_DELMEMBER, PREC_ASSIGN, TYP_OPERATOR, false, false},
239  {".?", TOK_CHKMEMBER, PREC_ASSIGN, TYP_OPERATOR, false, false},
240 
241  {",", TOK_COMMA, PREC_COMMA, TYP_SEPARATOR, false, false},
242  {"", TOK_TERM, PREC_TERMINATOR, TYP_TERMINATOR, false, false}};
243 int n_operators = sizeof binary_operators / sizeof binary_operators[0];
244 
246  {"+", TOK_UNPLUS, PREC_UNARY_OPS, TYP_UNARY_OPERATOR, false, false},
247  {"-", TOK_UNMINUS, PREC_UNARY_OPS, TYP_UNARY_OPERATOR, false, false},
248  {"!", TOK_LOG_NOT, PREC_UNARY_OPS, TYP_UNARY_OPERATOR, false, false},
249  {"~", TOK_BITWISE_NOT, PREC_UNARY_OPS, TYP_UNARY_OPERATOR, false, false},
250  {"@", TOK_FUNCREF, PREC_UNARY_OPS, TYP_FUNCREF, false, false}
251  // { "not", TOK_LOG_NOT, PREC_UNARY_OPS, TYP_UNARY_OPERATOR, false, false }
252  // "refto", TOK_REFTO, 12, TYP_UNARY_OPERATOR, false, false
253 };
254 int n_unary = sizeof unary_operators / sizeof unary_operators[0];
255 
257  // MBR_*, "name", read_only
258  {MBR_X, "x", true}, // 0
259  {MBR_Y, "y", true}, // 1
260  {MBR_Z, "z", true},
261  {MBR_NAME, "name", false},
262  {MBR_OBJTYPE, "objtype", true},
263  {MBR_GRAPHIC, "graphic", false}, // 5
264  {MBR_SERIAL, "serial", true},
265  {MBR_COLOR, "color", false},
266  {MBR_HEIGHT, "height", true},
267  {MBR_FACING, "facing", false},
268  {MBR_DIRTY, "dirty", true}, // 10
269  {MBR_WEIGHT, "weight", true},
270  {MBR_MULTI, "multi", true},
271  {MBR_AMOUNT, "amount", true}, // item
272  {MBR_LAYER, "layer", true},
273  {MBR_CONTAINER, "container", true}, // 15
274  {MBR_USESCRIPT, "usescript", false},
275  {MBR_EQUIPSCRIPT, "equipscript", false},
276  {MBR_UNEQUIPSCRIPT, "unequipscript", false},
277  {MBR_DESC, "desc", false},
278  {MBR_MOVABLE, "movable", false}, // 20
279  {MBR_INVISIBLE, "invisible", false},
280  {MBR_DECAYAT, "decayat", false},
281  {MBR_SELLPRICE, "sellprice", false},
282  {MBR_BUYPRICE, "buyprice", false},
283  {MBR_NEWBIE, "newbie", false}, // 25
284  {MBR_ITEM_COUNT, "item_count", true},
285  {MBR_WARMODE, "warmode", true}, // character
286  {MBR_GENDER, "gender", false},
287  {MBR_TRUEOBJTYPE, "trueobjtype", false},
288  {MBR_TRUECOLOR, "truecolor", false}, // 30
289  {MBR_AR_MOD, "ar_mod", false},
290  {MBR_HIDDEN, "hidden", false},
291  {MBR_CONCEALED, "concealed", false},
292  {MBR_FROZEN, "frozen", false},
293  {MBR_PARALYZED, "paralyzed", false}, // 35
294  {MBR_POISONED, "poisoned", false},
295  {MBR_STEALTHSTEPS, "stealthsteps", false},
296  {MBR_SQUELCHED, "squelched", true},
297  {MBR_DEAD, "dead", true},
298  {MBR_AR, "ar", true}, // 40
299  {MBR_BACKPACK, "backpack", true},
300  {MBR_WEAPON, "weapon", true},
301  {MBR_SHIELD, "shield", true},
302  {MBR_ACCTNAME, "acctname", true},
303  {MBR_ACCT, "acct", true}, // 45
304  {MBR_CMDLEVEL, "cmdlevel", false},
305  {MBR_CMDLEVELSTR, "cmdlevelstr", true},
306  {MBR_CRIMINAL, "criminal", true},
307  {MBR_IP, "ip", true},
308  {MBR_GOLD, "gold", true}, // 50
309  {MBR_TITLE_PREFIX, "title_prefix", false},
310  {MBR_TITLE_SUFFIX, "title_suffix", false},
311  {MBR_TITLE_GUILD, "title_guild", false},
312  {MBR_TITLE_RACE, "title_race", false},
313  {MBR_GUILDID, "guildid", true}, // 55
314  {MBR_GUILD, "guild", true},
315  {MBR_MURDERER, "murderer", false},
316  {MBR_ATTACHED, "attached", true},
317  {MBR_CLIENTVERSION, "clientversion", true},
318  {MBR_REPORTABLES, "reportables", true}, // 60
319  {MBR_SCRIPT, "script", false}, // npc
320  {MBR_NPCTEMPLATE, "npctemplate", true},
321  {MBR_MASTER, "master", true},
322  {MBR_PROCESS, "process", true},
323  {MBR_EVENTMASK, "eventmask", true}, // 65
324  {MBR_SPEECH_COLOR, "speech_color", false},
325  {MBR_SPEECH_FONT, "speech_font", false},
326  {MBR_USE_ADJUSTMENTS, "use_adjustments", false},
327  {MBR_RUN_SPEED, "run_speed", false},
328  {MBR_LOCKED, "locked", false}, // lockable //70
329  {MBR_CORPSETYPE, "corpsetype", true}, // corpse
330  {MBR_TILLERMAN, "tillerman", true}, // boat
331  {MBR_PORTPLANK, "portplank", true},
332  {MBR_STARBOARDPLANK, "starboardplank", true},
333  {MBR_HOLD, "hold", true}, // 75
334  {MBR_HAS_OFFLINE_MOBILES, "has_offline_mobiles", true},
335  {MBR_COMPONENTS, "components", true}, // house
336  {MBR_ITEMS, "items", true}, // multi
337  {MBR_MOBILES, "mobiles", true},
338  {MBR_XEAST, "xeast", false}, // map //80
339  {MBR_XWEST, "xwest", false},
340  {MBR_YNORTH, "ynorth", false},
341  {MBR_YSOUTH, "ysouth", false},
342  {MBR_GUMPWIDTH, "gumpwidth", false},
343  {MBR_GUMPHEIGHT, "gumpheight", false}, // 85
344  {MBR_ISOPEN, "isopen", true}, // door
345  {MBR_QUALITY, "quality", false}, // equipment
346  {MBR_HP, "hp", false},
347  {MBR_MAXHP_MOD, "maxhp_mod", false},
348  {MBR_MAXHP, "maxhp", true}, // 90
349  {MBR_DMG_MOD, "dmg_mod", false}, // weapon
350  {MBR_ATTRIBUTE, "attribute", true},
351  {MBR_INTRINSIC, "intrinsic", true},
352  {MBR_HITSCRIPT, "hitscript", false},
353  {MBR_AR_BASE, "ar_base", true}, // 95
354  {MBR_ONHIT_SCRIPT, "onhitscript", false},
355  {MBR_ENABLED, "enabled", true}, // account
356  {MBR_BANNED, "banned", true},
357  {MBR_USERNAMEPASSWORDHASH, "usernamepasswordhash", true},
358  {MBR_MEMBERS, "members", true}, // guild //100
359  {MBR_ALLYGUILDS, "allyguilds", true},
360  {MBR_ENEMYGUILDS, "enemyguilds", true},
361  {MBR_PID, "pid", true}, // script
362  {MBR_STATE, "state", true},
363  {MBR_INSTR_CYCLES, "instr_cycles", true}, // 105
364  {MBR_SLEEP_CYCLES, "sleep_cycles", true},
365  {MBR_CONSEC_CYCLES, "consec_cycles", true},
366  {MBR_PC, "pc", true},
367  {MBR_CALL_DEPTH, "call_depth", true},
368  {MBR_NUM_GLOBALS, "num_globals", true}, // 110
369  {MBR_VAR_SIZE, "var_size", true},
370  {MBR_REALM, "realm", true},
371  {MBR_UO_EXPANSION, "uo_expansion", true},
372  {MBR_CUSTOM, "custom", true}, // house
373  {MBR_GLOBALS, "globals", true}, // 115
374  {MBR_FOOTPRINT, "footprint", true},
375  {MBR_CLIENTINFO, "clientinfo", true},
376  {MBR_DELAY_MOD, "delay_mod", false},
377  {MBR_CREATEDAT, "createdat", true},
378  {MBR_OPPONENT, "opponent", true}, // 120
379  {MBR_CONNECTED, "connected", true},
380  {MBR_ATTACHED_TO, "attached_to", true},
381  {MBR_CONTROLLER, "controller", true},
382  {MBR_OWNERSERIAL, "ownerserial", true},
383  {MBR_DEFAULTCMDLEVEL, "defaultcmdlevel", true}, // 125
384  {MBR_UCLANG, "uclang", true},
385  {MBR_RACE, "race", false},
386  {MBR_TRADING_WITH, "trading_with", false},
387  {MBR_TRADE_CONTAINER, "trade_container", false},
388  {MBR_ALIGNMENT, "alignment", false}, // 130
389  {MBR_CURSOR, "cursor", false},
390  {MBR_GUMP, "gump", false},
391  {MBR_PROMPT, "prompt", false},
392  {MBR_STACKABLE, "stackable", false},
393  {MBR_MOVEMODE, "movemode", false}, // 135
394  {MBR_HITCHANCE_MOD, "hitchance_mod", false},
395  {MBR_EVASIONCHANCE_MOD, "evasionchance_mod", false},
396  {MBR_TILE_LAYER, "tile_layer", true},
397  {MBR_CLIENTVERSIONDETAIL, "clientver_detail", true},
398  {MBR_SAVEONEXIT, "saveonexit", true}, // 140
399  {MBR_FIRE_RESIST, "resist_fire", true},
400  {MBR_COLD_RESIST, "resist_cold", true},
401  {MBR_ENERGY_RESIST, "resist_energy", true},
402  {MBR_POISON_RESIST, "resist_poison", true},
403  {MBR_PHYSICAL_RESIST, "resist_physical", true}, // 145
404  {MBR_FIRE_RESIST_MOD, "resist_fire_mod", true},
405  {MBR_COLD_RESIST_MOD, "resist_cold_mod", true},
406  {MBR_ENERGY_RESIST_MOD, "resist_energy_mod", true},
407  {MBR_POISON_RESIST_MOD, "resist_poison_mod", true},
408  {MBR_PHYSICAL_RESIST_MOD, "resist_physical_mod", true}, // 150
409  {MBR_STATCAP, "statcap", false},
410  {MBR_SKILLCAP, "skillcap", false},
411  {MBR_LUCK, "luck", false},
412  {MBR_FOLLOWERSMAX, "followers_max", false},
413  {MBR_TITHING, "tithing", false}, // 155
414  {MBR_FOLLOWERS, "followers", false},
415  {MBR_FIRE_DAMAGE, "damage_fire", true},
416  {MBR_COLD_DAMAGE, "damage_cold", true},
417  {MBR_ENERGY_DAMAGE, "damage_energy", true},
418  {MBR_POISON_DAMAGE, "damage_poison", true}, // 160
419  {MBR_PHYSICAL_DAMAGE, "damage_physical", true},
420  {MBR_FIRE_DAMAGE_MOD, "damage_fire_mod", true},
421  {MBR_COLD_DAMAGE_MOD, "damage_cold_mod", true},
422  {MBR_ENERGY_DAMAGE_MOD, "damage_energy_mod", true},
423  {MBR_POISON_DAMAGE_MOD, "damage_poison_mod", true}, // 165
424  {MBR_PHYSICAL_DAMAGE_MOD, "damage_physical_mod", true},
425  {MBR_PARTY, "party", true},
426  {MBR_LEADER, "leader", true},
427  {MBR_PARTYLOOT, "partycanloot", true},
428  {MBR_CANDIDATE_OF_PARTY, "candidate_of_party", true}, // 170
429  {MBR_CANDIDATES, "candidates", true},
430  {MBR_MOVECOST_WALK, "movecost_walk_mod", true},
431  {MBR_MOVECOST_RUN, "movecost_run_mod", true},
432  {MBR_MOVECOST_WALK_MOUNTED, "movecost_walk_mounted_mod", true},
433  {MBR_MOVECOST_RUN_MOUNTED, "movecost_run_mounted_mod", true}, // 175
434  {MBR_AGGRESSORTO, "aggressorto", true},
435  {MBR_LAWFULLYDAMAGED, "lawfullydamaged", true},
436  {MBR_GETGOTTENBY, "getgottenby", true},
437  {MBR_UO_EXPANSION_CLIENT, "uo_expansion_client", true},
438  {MBR_CLIENTTYPE, "clienttype", true}, // 180
439  {MBR_DEAFENED, "deafed", true},
440  {MBR_CLIENT, "client", true},
441  {MBR_TYPE, "type", true},
442  {MBR_ATTRIBUTES, "attributes", true},
443  {MBR_EDITING, "house_editing", true}, // 185
444  {MBR_HOUSEPARTS, "house_parts", true},
445  {MBR_DOUBLECLICKRANGE, "doubleclickrange", false},
446  {MBR_MOUNTEDSTEPS, "mountedsteps", false},
447  // New boat stuff start
448  {MBR_ROPE, "rope", true},
449  {MBR_WHEEL, "wheel", true}, // 190
450  {MBR_HULL, "hull", true},
451  {MBR_TILLER, "tiller", true},
452  {MBR_RUDDER, "rudder", true},
453  {MBR_SAILS, "sails", true},
454  {MBR_STORAGE, "storage", true}, // 195
455  {MBR_WEAPONSLOT, "weaponslot", true},
456  // New boat stuff end
457  {MBR_MULTIID, "multiid", true},
458  {MBR_TRADEWINDOW, "tradewindow", true},
459  {MBR_LASTCOORD, "lastcoord", true},
460  {MBR_FACETID, "facetid", true}, // 200
461  {MBR_EDITABLE, "editable", true},
462  {MBR_ACTIVE_SKILL, "active_skill", true},
463  {MBR_CASTING_SPELL, "casting_spell", true},
464  {MBR_CARRYINGCAPACITY_MOD, "carrying_capacity_mod", false},
465  {MBR_MAX_ITEMS_MOD, "max_items_mod", false}, // 205
466  {MBR_MAX_WEIGHT_MOD, "max_weight_mod", false},
467  {MBR_MAX_SLOTS_MOD, "max_slots_mod", false},
468  {MBR_SPEED_MOD, "speed_mod", false},
469  {MBR_NAME_SUFFIX, "name_suffix", false},
470  {MBR_TEMPORALLY_CRIMINAL, "temporally_criminal", true}, // 210
471  {MBR_LAST_TEXTCOLOR, "last_textcolor", true},
472  {MBR_INSURED, "insured", false},
473  {MBR_LAST_ACTIVITY_AT, "last_activity_at", false},
474  {MBR_LAST_PACKET_AT, "last_packet_at", false},
475  {MBR_HOUSE, "house", true}, // 215, Item
476  {MBR_SPECIFIC_NAME, "specific_name", true},
477  {MBR_CARRYINGCAPACITY, "carrying_capacity", true},
478  {MBR_NO_DROP, "no_drop", false},
479  {MBR_NO_DROP_EXCEPTION, "no_drop_exception", false},
480  {MBR_PORT, "port", false},
481 };
482 int n_objmembers = sizeof object_members / sizeof object_members[0];
483 ObjMember* getKnownObjMember( const char* token )
484 {
485  static auto cache = []() -> std::unordered_map<std::string, ObjMember*> {
486  std::unordered_map<std::string, ObjMember*> m;
487  for ( int i = 0; i < n_objmembers; ++i )
488  {
489  m[object_members[i].code] = &object_members[i];
490  }
491  return m;
492  }();
493  std::string temp( token );
494  std::transform( temp.begin(), temp.end(), temp.begin(),
495  []( char c ) { return static_cast<char>(::tolower( c ) ); } );
496  auto member = cache.find( temp );
497  if ( member != cache.end() )
498  return member->second;
499  return nullptr;
500 }
502 {
503  if ( id >= n_objmembers )
504  return nullptr;
505  else
506  return &( object_members[id] );
507 }
508 
510  {MTH_ISA, "isa", false}, // 0
511  {MTH_SET_MEMBER, "set_member", false}, // 1
512  {MTH_GET_MEMBER, "get_member", false},
513  {MTH_SETPOISONED, "setpoisoned", false},
514  {MTH_SETPARALYZED, "setparalyzed", false},
515  {MTH_SETCRIMINAL, "setcriminal", false}, // 5
516  {MTH_SETLIGHTLEVEL, "setlightlevel", false},
517  {MTH_SQUELCH, "squelch", false},
518  {MTH_ENABLE, "enable", false},
519  {MTH_DISABLE, "disable", false},
520  {MTH_ENABLED, "enabled", false}, // 10
521  {MTH_SETCMDLEVEL, "setcmdlevel", false},
522  {MTH_SPENDGOLD, "spendgold", false},
523  {MTH_SETMURDERER, "setmurderer", false},
524  {MTH_REMOVEREPORTABLE, "removereportable", false},
525  {MTH_GETGOTTENITEM, "getgottenitem", false}, // 15
526  {MTH_CLEARGOTTENITEM, "cleargottenitem", false},
527  {MTH_SETWARMODE, "setwarmode", false},
528  {MTH_SETMASTER, "setmaster", false}, // npc
529  {MTH_MOVE_OFFLINE_MOBILES, "move_offline_mobiles", false}, // boat
530  {MTH_SETCUSTOM, "setcustom", false}, // house //20
531  {MTH_GETPINS, "getpins", false}, // map
532  {MTH_INSERTPIN, "insertpin", false},
533  {MTH_APPENDPIN, "appendpin", false},
534  {MTH_ERASEPIN, "erasepin", false},
535  {MTH_OPEN, "open", false}, // door //25
536  {MTH_CLOSE, "close", false},
537  {MTH_TOGGLE, "toggle", false},
538  {MTH_BAN, "ban", false}, // account
539  {MTH_UNBAN, "unban", false},
540  {MTH_SETPASSWORD, "setpassword", false}, // 30
541  {MTH_CHECKPASSWORD, "checkpassword", false},
542  {MTH_SETNAME, "setname", false},
543  {MTH_GETCHARACTER, "getcharacter", false},
544  {MTH_DELETECHARACTER, "deletecharacter", false},
545  {MTH_GETPROP, "getprop", false}, // 35
546  {MTH_SETPROP, "setprop", false},
547  {MTH_ERASEPROP, "eraseprop", false},
548  {MTH_PROPNAMES, "propnames", false},
549  {MTH_ISMEMBER, "ismember", false}, // guild
550  {MTH_ISALLYGUILD, "isallyguild", false}, // 40
551  {MTH_ISENEMYGUILD, "isenemyguild", false},
552  {MTH_ADDMEMBER, "addmember", false},
553  {MTH_ADDALLYGUILD, "addallyguild", false},
554  {MTH_ADDENEMYGUILD, "addenemyguild", false},
555  {MTH_REMOVEMEMBER, "removemember", false}, // 45
556  {MTH_REMOVEALLYGUILD, "removeallyguild", false},
557  {MTH_REMOVEENEMYGUILD, "removeenemyguild", false},
558  {MTH_SIZE, "size", false}, // ARRAY
559  {MTH_ERASE, "erase", false},
560  {MTH_INSERT, "insert", false}, // 50
561  {MTH_SHRINK, "shrink", false},
562  {MTH_APPEND, "append", false},
563  {MTH_REVERSE, "reverse", false},
564  {MTH_SORT, "sort", false}, // dict
565  {MTH_EXISTS, "exists", false}, // 55
566  {MTH_KEYS, "keys", false},
567  {MTH_SENDPACKET, "sendpacket", false}, // packet
568  {MTH_SENDAREAPACKET, "sendareapacket", false},
569  {MTH_GETINT8, "getint8", false},
570  {MTH_GETINT16, "getint16", false}, // 60
571  {MTH_GETINT32, "getint32", false},
572  {MTH_SETINT8, "setint8", false},
573  {MTH_SETINT16, "setint16", false},
574  {MTH_SETINT32, "setint32", false},
575  {MTH_GETSTRING, "getstring", false}, // 65
576  {MTH_GETUNICODESTRING, "getunicodestring", false},
577  {MTH_SETSTRING, "setstring", false},
578  {MTH_SETUNICODESTRING, "setunicodestring", false},
579  {MTH_GETSIZE, "getsize", false},
580  {MTH_SETSIZE, "setsize", false}, // 70
581  {MTH_CREATEELEMENT, "createelement", false}, // datastore
582  {MTH_FINDELEMENT, "findelement", false},
583  {MTH_DELETEELEMENT, "deleteelement", false},
584  {MTH_SENDEVENT, "sendevent", false}, // script
585  {MTH_KILL, "kill", false}, // 75
586  {MTH_LOADSYMBOLS, "loadsymbols", false},
587  {MTH_SET_UO_EXPANSION, "set_uo_expansion", false},
588  {MTH_CLEAR_EVENT_QUEUE, "clear_event_queue", false},
589  {MTH_ADD_COMPONENT, "add_component", false},
590  {MTH_ERASE_COMPONENT, "erase_component", false}, // 80
591  {MTH_DELETE, "delete", false},
592  {MTH_SPLIT, "split", false},
593  {MTH_MOVE_CHAR, "move_char", false},
594  {MTH_GETINT16FLIPPED, "getint16flipped", false},
595  {MTH_GETINT32FLIPPED, "getint32flipped", false}, // 85
596  {MTH_SETINT16FLIPPED, "setint16flipped", false},
597  {MTH_SETINT32FLIPPED, "setint32flipped", false},
598  {MTH_GETCORPSE, "getcorpse", false},
599  {MTH_SETDEFAULTCMDLEVEL, "setdefaultcmdlevel", false},
600  {MTH_PRIVILEGES, "privileges", false}, // 90
601  {MTH_GETUNICODESTRINGFLIPPED, "getunicodestringflipped", false},
602  {MTH_SETUNICODESTRINGFLIPPED, "setunicodestringflipped", false},
603  {MTH_ADD_CHARACTER, "addcharacter", false},
604  {MTH_SET_SWINGTIMER, "setswingtimer", false},
605  {MTH_ATTACK_ONCE, "attack_once", false}, // 95
606  {MTH_SETFACING, "setfacing", false},
607  {MTH_COMPAREVERSION, "compareversion", false},
608  {MTH_SETLEADER, "setleader", false},
609  {MTH_ADDCANDIDATE, "addcandidate", false},
610  {MTH_REMOVECANDIDATE, "removecandidate", false}, // 100
611  {MTH_RANDOMENTRY, "randomentry", false},
612  {MTH_SEEK, "seek", false},
613  {MTH_PEEK, "peek", false},
614  {MTH_TELL, "tell", false},
615  {MTH_FLUSH, "flush", false}, // 105
616  {MTH_GETSINT8, "getsint8", false},
617  {MTH_GETSINT16, "getsint16", false},
618  {MTH_GETSINT32, "getsint32", false},
619  {MTH_SETSINT8, "setsint8", false},
620  {MTH_SETSINT16, "setsint16", false}, // 110
621  {MTH_SETSINT32, "setsint32", false},
622  {MTH_SETAGGRESSORTO, "setaggressorto", false},
623  {MTH_SETLAWFULLYDAMAGEDTO, "setlawfullydamagedto", false},
624  {MTH_CLEARAGGRESSORTO, "clearaggressorto", false},
625  {MTH_CLEARLAWFULLYDAMAGEDTO, "clearlawfullydamagedto", false}, // 115
626  {MTH_HASSPELL, "hasspell", false},
627  {MTH_SPELLS, "spells", false},
628  {MTH_REMOVESPELL, "removespell", false},
629  {MTH_ADDSPELL, "addspell", false},
630  {MTH_DEAF, "deaf", false}, // 120
631  {MTH_SETSEASON, "setseason", false},
632  {MTH_NEXTSIBLING, "nextxmlsibling", false},
633  {MTH_FIRSTCHILD, "firstxmlchild", false},
634  {MTH_SAVEXML, "savexml", false},
635  {MTH_APPENDNODE, "appendxmlnode", false}, // 125
636  {MTH_SETDECLARATION, "setxmldeclaration", false},
637  {MTH_SETATTRIBUTE, "setxmlattribute", false},
638  {MTH_REMOVEATTRIBUTE, "removexmlattribute", false},
639  {MTH_REMOVENODE, "removexmlnode", false},
640  {MTH_APPENDTEXT, "appendxmltext", false}, // 130
641  {MTH_XMLTOSTRING, "xmltostring", false},
642  {MTH_APPENDXMLCOMMENT, "appendxmlcomment", false},
643  {MTH_ADD_HOUSE_PART, "addhousepart", false},
644  {MTH_ERASE_HOUSE_PART, "erasehousepart", false},
645  {MTH_ACCEPT_COMMIT, "acceptcommit", false}, // 135
646  {MTH_SPLITSTACK_AT, "splitstackat", false},
647  {MTH_SPLITSTACK_INTO, "splitstackinto", false},
648  {MTH_CANCEL_EDITING, "cancelediting", false},
649  {MTH_CLONENODE, "clonenode", false},
650  {MTH_HAS_EXISTING_STACK, "hasexistingstack", false}, // 140
651  {MTH_LENGTH, "length", false},
652  {MTH_JOIN, "join", false},
653  {MTH_FIND, "find", false},
654  {MTH_UPPER, "upper", false},
655  {MTH_LOWER, "lower", false}, // 145
656  {MTH_FORMAT, "format", false},
657  {MTH_DISABLE_SKILLS_FOR, "disableskillsfor", false},
658  {MTH_CYCLE, "cycle", false},
659  {MTH_ADD_BUFF, "addbuff", false},
660  {MTH_DEL_BUFF, "delbuff", false}, // 150
661  {MTH_CLEAR_BUFFS, "clearbuffs", false},
662  {MTH_CALL, "call", false},
663  {MTH_SORTEDINSERT, "sorted_insert", false},
664 };
665 int n_objmethods = sizeof object_methods / sizeof object_methods[0];
666 ObjMethod* getKnownObjMethod( const char* token )
667 {
668  // cache needs to hold a pointer to the original structure! eprog_read sets the override member
669  static auto cache = []() -> std::unordered_map<std::string, ObjMethod*> {
670  std::unordered_map<std::string, ObjMethod*> m;
671  for ( int i = 0; i < n_objmethods; ++i )
672  {
673  m[object_methods[i].code] = &object_methods[i];
674  }
675  return m;
676  }();
677  std::string temp( token );
678  std::transform( temp.begin(), temp.end(), temp.begin(),
679  []( char c ) { return static_cast<char>(::tolower( c ) ); } );
680  auto method = cache.find( temp );
681  if ( method != cache.end() )
682  return method->second;
683  return nullptr;
684 }
686 {
687  if ( id >= n_objmethods )
688  return nullptr;
689  else
690  return &( object_methods[id] );
691 }
692 
694 {
695  for ( int i = 0; i < n_objmethods; i++ )
696  {
697  if ( object_methods[i].id != i )
698  {
699  INFO_PRINT << "ERROR: Object Method definition of " << object_methods[i].code
700  << " has an invalid index!\n";
701  }
702  auto c = reinterpret_cast<unsigned char*>( object_methods[i].code );
703  while ( *c )
704  {
705  if ( *c != tolower( *c ) )
706  {
707  INFO_PRINT << "ERROR: Object Method definition of " << object_methods[i].code
708  << " is not lowercase!\n";
709  break;
710  }
711  ++c;
712  }
713  }
714  for ( int i = 0; i < n_objmembers; i++ )
715  {
716  if ( object_members[i].id != i )
717  {
718  INFO_PRINT << "ERROR: Object Member definition of " << object_members[i].code
719  << " has an invalid index!\n";
720  }
721  auto c = reinterpret_cast<unsigned char*>( object_members[i].code );
722  while ( *c )
723  {
724  if ( *c != tolower( *c ) )
725  {
726  INFO_PRINT << "ERROR: Object Member definition of " << object_members[i].code
727  << " is not lowercase!\n";
728  break;
729  }
730  ++c;
731  }
732  }
733 }
735 
736 void matchOperators( Operator* oplist, int n_ops, char* buf, int* nPartial,
737  Operator** pTotalMatchOperator )
738 {
739  // all operators are 1 or 2 characters.
740  // they also don't have case.
741  int lenbuf = buf[1] ? 2 : 1;
742 
743  *nPartial = 0;
744  *pTotalMatchOperator = NULL;
745 
746  if ( lenbuf == 1 )
747  {
748  Operator* op = &oplist[0];
749  for ( int i = 0; i < n_ops; ++i, ++op )
750  {
751  if ( op->code[0] == buf[0] )
752  {
753  if ( op->code[1] == '\0' )
754  {
755  ( *pTotalMatchOperator ) = op;
756  if ( !op->ambig )
757  return;
758  }
759  else
760  {
761  ( *nPartial )++;
762  }
763  }
764  }
765  }
766  else // lenbuf == 2
767  {
768  Operator* op = &oplist[0];
769  for ( int i = 0; i < n_ops; ++i, ++op )
770  {
771  if ( op->code[0] == buf[0] && op->code[1] == buf[1] )
772  {
773  ( *pTotalMatchOperator ) = op;
774  return;
775  }
776  }
777  }
778 }
779 
780 /*
781 void matchOperators(char *buf, int *nPartial, Operator** ppMatch)
782 {
783 matchOperators(binary_operators, n_operators,
784 buf, nPartial, ppMatch);
785 }
786 void matchUnaryOperators(char *buf, int *nPartial, Operator** ppMatch)
787 {
788 matchOperators(unary_operators, n_unary,
789 buf, nPartial, ppMatch);
790 }
791 */
792 
793 // FIXME this really should be a word, type, and id
794 // (or better yet, eliminate type altogether.)
795 // reserved words first get read out as literals, then
796 // are recognized to be reserved words.
797 // the "and", "or", and "not" operators won't be recognized
798 // right, for the moment.
799 
800 typedef struct
801 {
802  const char* word;
807 } ReservedWord;
808 
809 
811  {"if", RSV_ST_IF, TYP_RESERVED, PREC_TERMINATOR, false},
812  {"then", RSV_THEN, TYP_RESERVED, PREC_TERMINATOR, false},
813  {"elseif", RSV_ELSEIF, TYP_RESERVED, PREC_TERMINATOR, false},
814  {"endif", RSV_ENDIF, TYP_RESERVED, PREC_TERMINATOR, false},
815  {"else", RSV_ELSE, TYP_RESERVED, PREC_TERMINATOR, false},
816  {"_OptionBracketed", RSV_OPTION_BRACKETED, TYP_RESERVED, PREC_TERMINATOR, false},
817 
818  {"goto", RSV_GOTO, TYP_RESERVED, PREC_TERMINATOR, false},
819  {"gosub", RSV_GOSUB, TYP_RESERVED, PREC_TERMINATOR, false},
820  {"return", RSV_RETURN, TYP_RESERVED, PREC_TERMINATOR, false},
821 
822  // { "global", RSV_GLOBAL, TYP_RESERVED, PREC_DEPRECATED, true }, // internal only
823  // { "local", RSV_LOCAL, TYP_RESERVED, PREC_DEPRECATED, true }, // internal only
824  {"const", RSV_CONST, TYP_RESERVED, PREC_TERMINATOR, false},
825  {"var", RSV_VAR, TYP_RESERVED, PREC_TERMINATOR, false},
826 
827  // { "begin", RSV_BEGIN, TYP_RESERVED, PREC_DEPRECATED, true }, // deprecated
828  // { "end", RSV_ENDB, TYP_RESERVED, PREC_DEPRECATED, true }, // deprecated
829 
830  {"do", RSV_DO, TYP_RESERVED, PREC_TERMINATOR, false},
831  {"dowhile", RSV_DOWHILE, TYP_RESERVED, PREC_TERMINATOR, false},
832  {"while", RSV_WHILE, TYP_RESERVED, PREC_TERMINATOR, false},
833  {"endwhile", RSV_ENDWHILE, TYP_RESERVED, PREC_TERMINATOR, false},
834 
835  {"exit", RSV_EXIT, TYP_RESERVED, PREC_TERMINATOR, false},
836 
837  {"declare", RSV_DECLARE, TYP_RESERVED, PREC_TERMINATOR, false},
838 
839  {"function", RSV_FUNCTION, TYP_RESERVED, PREC_TERMINATOR, false},
840  {"endfunction", RSV_ENDFUNCTION, TYP_RESERVED, PREC_TERMINATOR, false},
841  {"exported", RSV_EXPORTED, TYP_RESERVED, PREC_TERMINATOR, false},
842 
843  {"use", RSV_USE_MODULE, TYP_RESERVED, PREC_TERMINATOR, false},
844  {"include", RSV_INCLUDE_FILE, TYP_RESERVED, PREC_TERMINATOR, false},
845 
846  {"break", RSV_BREAK, TYP_RESERVED, PREC_TERMINATOR, false},
847  {"continue", RSV_CONTINUE, TYP_RESERVED, PREC_TERMINATOR, false},
848 
849  {"for", RSV_FOR, TYP_RESERVED, PREC_TERMINATOR, false},
850  {"endfor", RSV_ENDFOR, TYP_RESERVED, PREC_TERMINATOR, false},
851  {"to", RSV_TO, TYP_RESERVED, PREC_TERMINATOR, false},
852  {"next", RSV_NEXT, TYP_RESERVED, PREC_TERMINATOR, false},
853 
854  {"foreach", RSV_FOREACH, TYP_RESERVED, PREC_TERMINATOR, false},
855  {"endforeach", RSV_ENDFOREACH, TYP_RESERVED, PREC_TERMINATOR, false},
856 
857  {"repeat", RSV_REPEAT, TYP_RESERVED, PREC_TERMINATOR, false},
858  {"until", RSV_UNTIL, TYP_RESERVED, PREC_TERMINATOR, false},
859 
860  {"program", RSV_PROGRAM, TYP_RESERVED, PREC_TERMINATOR, false},
861  {"endprogram", RSV_ENDPROGRAM, TYP_RESERVED, PREC_TERMINATOR, false},
862 
863  {"case", RSV_SWITCH, TYP_RESERVED, PREC_TERMINATOR, false},
864  // { "case", RSV_CASE, TYP_RESERVED, PREC_TERMINATOR, false },
865  {"default", RSV_DEFAULT, TYP_RESERVED, PREC_TERMINATOR, false},
866  {"endcase", RSV_ENDSWITCH, TYP_RESERVED, PREC_TERMINATOR, false},
867 
868  {"enum", RSV_ENUM, TYP_RESERVED, PREC_TERMINATOR, false},
869  {"endenum", RSV_ENDENUM, TYP_RESERVED, PREC_TERMINATOR, false},
870 
871  {"downto", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
872  {"step", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
873  {"reference", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
874  {"out", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
875  {"inout", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
876  // { "ByRef", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false },
877  {"ByVal", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
878 
879  {"string", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
880  {"long", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
881  {"integer", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
882  {"unsigned", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
883  {"signed", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
884  {"real", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
885  {"float", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
886  {"double", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
887  {"as", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
888  {"is", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
889 
890  {"and", TOK_AND, TYP_OPERATOR, PREC_LOGAND, false},
891  {"or", TOK_OR, TYP_OPERATOR, PREC_LOGOR, false},
893  {"byref", TOK_REFTO, TYP_RESERVED, PREC_TERMINATOR, false}, // UNARY_OPERATOR, 12 },
894  {"unused", TOK_UNUSED, TYP_RESERVED, PREC_TERMINATOR, false},
895  {"error", TOK_ERROR, TYP_OPERAND, PREC_TERMINATOR, false},
896  {"hash", RSV_FUTURE, TYP_RESERVED, PREC_TERMINATOR, false},
897  {"dictionary", TOK_DICTIONARY, TYP_OPERAND, PREC_TERMINATOR, false},
898  {"struct", TOK_STRUCT, TYP_OPERAND, PREC_TERMINATOR, false},
899  {"array", TOK_ARRAY, TYP_OPERAND, PREC_TERMINATOR, false},
900  {"stack", TOK_STACK, TYP_OPERAND, PREC_TERMINATOR, false},
901  {"in", TOK_IN, TYP_OPERATOR, PREC_EQUALTO, false}
902  // { "bitand", TOK_BITAND, TYP_OPERATOR, PREC_BITAND },
903  // { "bitxor", TOK_BITXOR, TYP_OPERATOR, PREC_BITXOR },
904  // { "bitor", TOK_BITOR, TYP_OPERATOR, PREC_BITOR }
905  /* "/""*", RSV_COMMENT_START,
906  "*""/", RSV_COMMENT_END,
907  "/""/", RSV_COMMENT_TO_EOL,
908  "--", RSV_COMMENT_TO_EOL
909  */
910 };
911 unsigned n_reserved = sizeof reserved_words / sizeof reserved_words[0];
912 
913 typedef std::map<std::string, ReservedWord*, Clib::ci_cmp_pred> ReservedWords;
914 ReservedWords reservedWordsByName;
915 static void init_tables()
916 {
917  static std::once_flag flag;
918  std::call_once( flag, []() {
919  for ( unsigned i = 0; i < n_reserved; ++i )
920  {
921  reservedWordsByName[reserved_words[i].word] = &reserved_words[i];
922  }
923  } );
924 }
925 
926 void Parser::write_words( std::ostream& os )
927 {
928  os << "Reserved:" << std::endl;
929  for ( unsigned i = 0; i < n_reserved; ++i )
930  {
931  os << reserved_words[i].word << ( reserved_words[i].deprecated ? " (deprecated)" : "" )
932  << std::endl;
933  }
934  os << std::endl;
935  os << "Binary:" << std::endl;
936  for ( int i = 0; i < n_operators; ++i )
937  {
938  os << binary_operators[i].code << ( binary_operators[i].deprecated ? " (deprecated)" : "" )
939  << std::endl;
940  }
941  os << std::endl;
942  os << "Unary:" << std::endl;
943  for ( int i = 0; i < n_unary; ++i )
944  {
945  os << unary_operators[i].code << ( unary_operators[i].deprecated ? " (deprecated)" : "" )
946  << std::endl;
947  }
948  os << std::endl;
949  os << "Methodlist:" << std::endl;
950  for ( int i = 0; i < n_objmethods; i++ )
951  {
952  os << object_methods[i].id << " " << object_methods[i].code << std::endl;
953  }
954  os << std::endl;
955  os << "Memberlist:" << std::endl;
956  for ( int i = 0; i < n_objmembers; i++ )
957  {
958  os << object_members[i].id << " " << object_members[i].code << std::endl;
959  }
960 }
961 
962 #if 0
963  void matchReservedWords(char *buf,
964  int *nPartial,
965  int *nTotal)
966  {
967  int lenbuf = strlen(buf);
968  assert(nPartial && nTotal);
969  *nPartial = 0;
970  *nTotal = 0;
971  for(int i = 0; i < n_reserved; i++)
972  {
973  if (strnicmp(reserved_words[i].word, buf, lenbuf)==0)
974  (*nPartial)++;
975  if (stricmp(reserved_words[i].word, buf)==0)
976  (*nTotal)++;
977  }
978  }
979 #endif
980 
981  /*
982  WTF is going on in this function? It seems like it waits for a match, followed
983  by a nonmatch? eh?
984 
985  What does this mean for variables like "IfDone" etc?
986  */
987 
988 #if 0
989  int Parser::tryReservedWord(Token& tok, char *t, char **s)
990  {
991  char opbuf[10];
992  int bufp = 0;
993  int thisMatchPartial, thisMatchTotal;
994  int lastMatchTotal = 0;
995 
996  while (t && *t) {
997  /* let's try to match it as we go. */
998  if (bufp==10) { err = PERR_BADTOKEN; return -1; }
999  opbuf[bufp++] = *t++;
1000  opbuf[bufp] = '\0';
1001  matchReservedWords(opbuf, &thisMatchPartial, &thisMatchTotal);
1002  if (!thisMatchPartial) { /* can't match a bloody thing! */
1003  switch(lastMatchTotal) {
1004  case 0:
1005  return 0; // this just wasn't a reserved word..
1006  case 1: // this is the only way it will work..
1007  // here, we don't match now but if we don't count
1008  // this character, it was a unique match.
1009  opbuf[bufp-1] = '\0';
1010  tok.nulStr();
1011  recognize_reserved_word(tok, opbuf);
1012  *s = t-1;
1013  return 1;
1014  case 2: // here, with this character there is no match
1015  // but before there were multiple matches.
1016  // really shouldn't happen.
1017  err = PERR_BADOPER;
1018  return -1;
1019  }
1020  } else { /* this partially matches.. */
1021  // "Remember....."
1022  lastMatchTotal = thisMatchTotal;
1023  }
1024  }
1025 
1026  if (thisMatchTotal == 1) {
1027  tok.nulStr();
1028  recognize_reserved_word( tok, opbuf );
1029  *s = t;
1030  return 1;
1031  }
1032 
1033  return 0; // didn't find one!
1034  }
1035 #endif
1036 
1048 int Parser::tryOperator( Token& tok, const char* t, const char** s, Operator* opList, int n_ops,
1049  char* opbuf )
1050 {
1051  int bufp = 0;
1052  int thisMatchPartial;
1053  Operator* pLastMatch = NULL;
1054  Operator* pMatch = NULL;
1055 
1056  while ( t && *t )
1057  {
1058  // if (strchr(operator_brk, *t)) mustBeOperator = 1;
1059 
1060  /* let's try to match it as we go. */
1061  if ( bufp == 4 )
1062  {
1063  err = PERR_BADTOKEN;
1064  return -1;
1065  }
1066  opbuf[bufp++] = *t++;
1067  opbuf[bufp] = '\0';
1068  matchOperators( opList, n_ops, opbuf, &thisMatchPartial, &pMatch );
1069  if ( !thisMatchPartial )
1070  {
1071  if ( pMatch )
1072  { // no partial matches, but a total match.
1073  break;
1074  }
1075  else if ( !pLastMatch )
1076  {
1077  // no total matches, no partial matches.
1078  return 0;
1079  }
1080  else // (pLastMatch)
1081  {
1082  // had a match before, but no partials this time.
1083  break;
1084  }
1085  }
1086  else
1087  { /* this partially matches.. */
1088  // "Remember....."
1089  if ( pMatch )
1090  {
1091  pLastMatch = pMatch;
1092  }
1093  }
1094  }
1095 
1096  if ( pMatch == NULL )
1097  pMatch = pLastMatch;
1098 
1099  if ( pMatch )
1100  {
1101  *s += strlen( pMatch->code );
1102 
1103  tok.module = Mod_Basic;
1104  tok.id = pMatch->id;
1105  tok.type = pMatch->type;
1106  tok.precedence = pMatch->precedence;
1107  tok.deprecated = pMatch->deprecated;
1108 
1109  tok.setStr( pMatch->code );
1110  return 1;
1111  }
1112 
1113  return 0; // didn't find one!
1114 }
1115 
1124 {
1125  int res;
1126  char opbuf[10];
1127 
1128  res = tryOperator( tok, ctx.s, &ctx.s, binary_operators, n_operators, opbuf );
1129 
1130  return res;
1131 }
1132 
1141 {
1142  int res;
1143  char opbuf[10];
1144 
1145  res = tryOperator( tok, ctx.s, &ctx.s, unary_operators, n_unary, opbuf );
1146 
1147  return res;
1148 }
1149 
1158 {
1159  if ( isdigit( ctx.s[0] ) || ctx.s[0] == '.' )
1160  {
1161  char *endptr, *endptr2;
1162  int l = strtol( ctx.s, &endptr, 0 );
1163  double d = strtod( ctx.s, &endptr2 );
1164 
1165  // 2015-01-21 Bodom: weird trick to remove an unwanted feature from Microsoft compiler
1166  // interpreting 'd' as 'e' (exponent), but 'd' in UO means dice,
1167  // leading to confusion
1168  // TODO: The best solution would be to reimplement the int/double parsing
1169  if ( !( ctx.s[0] == '0' && ctx.s[1] && ( ctx.s[1] == 'x' || ctx.s[1] == 'X' ) ) )
1170  {
1171  // This is not hex, so no 'd' can be valid
1172  for ( const char* i = ctx.s; i < endptr2; i++ )
1173  {
1174  if ( *i == 'd' || *i == 'D' )
1175  {
1176  // A 'd' has been eaten, bug could have occurred:
1177  // re-perform parsing on a cleaned version of the string
1178  size_t safelen = i - ctx.s + 1;
1179  std::unique_ptr<char[]> safeptr( new char[safelen]() );
1180  strncpy( safeptr.get(), ctx.s, safelen - 1 );
1181  d = strtod( safeptr.get(), &endptr2 );
1182  size_t newlen = endptr2 - safeptr.get();
1183  endptr2 = const_cast<char*>( ctx.s + newlen );
1184  break;
1185  }
1186  }
1187  }
1188 
1189  tok.type = TYP_OPERAND;
1190  if ( endptr >= endptr2 )
1191  { // long got more out of it, we'll go with that
1192  tok.id = TOK_LONG;
1193  tok.lval = l;
1194  ctx.s = endptr;
1195  return 1;
1196  }
1197  else
1198  {
1199  tok.id = TOK_DOUBLE;
1200  tok.dval = d;
1201  ctx.s = endptr2;
1202  return 1;
1203  }
1204  }
1205  return 0; // not numeric
1206 }
1207 
1216 {
1217  if ( ctx.s[0] == '\"' )
1218  {
1219  const char* end = &ctx.s[1];
1220  std::string lit;
1221  bool escnext = false; // true when waiting for 2nd char in an escape sequence
1222  u8 hexnext = 0; // tells how many more chars in a \xNN escape sequence
1223  char hexstr[3]; // will contain the \x escape chars to be processed
1224  memset( hexstr, 0, 3 );
1225 
1226  for ( ;; )
1227  {
1228  if ( !*end )
1229  {
1231  return -1;
1232  }
1233 
1234  passert_always_r( !( escnext && hexnext ),
1235  "Bug in the compiler. Please report this on the forums." );
1236 
1237  if ( escnext )
1238  {
1239  // waiting for 2nd character after a backslash
1240  escnext = false;
1241  if ( *end == 'n' )
1242  lit += '\n';
1243  else if ( *end == 't' )
1244  lit += '\t';
1245  else if ( *end == 'x' )
1246  hexnext = 2;
1247  else
1248  lit += *end;
1249  }
1250  else if ( hexnext )
1251  {
1252  // waiting for next (two) chars in hex escape sequence (eg. \xFF)
1253  hexstr[2 - hexnext] = *end;
1254  if ( !--hexnext )
1255  {
1256  char* endptr;
1257  char ord = static_cast<char>( strtol( hexstr, &endptr, 16 ) );
1258  if ( *endptr != '\0' )
1259  {
1260  err = PERR_INVESCAPE;
1261  return -1;
1262  }
1263  lit += ord;
1264  }
1265  }
1266  else
1267  {
1268  if ( *end == '\\' )
1269  escnext = true;
1270  else if ( *end == '\"' )
1271  break;
1272  else
1273  lit += *end;
1274  }
1275  ++end;
1276  }
1277  /*
1278  char *end = strchr(&ctx.s[1], '\"');
1279  if (!end)
1280  {
1281  err = PERR_UNTERMSTRING;
1282  return -1;
1283  }
1284  */
1285  // int len = end - ctx.s; // "abd" len = 5-1 = 4
1286  tok.id = TOK_STRING; // this is a misnomer I think!
1287  tok.type = TYP_OPERAND;
1288  tok.copyStr( lit.c_str() );
1289 
1290  ctx.s = end + 1; // skip past the ending delimiter
1291  return 1;
1292  }
1293  else if ( isalpha( ctx.s[0] ) || ctx.s[0] == '_' )
1294  { // we have a variable/label/verb.
1295  const char* end = ctx.s;
1296  while ( *end && !isspace( *end ) && strchr( ident_allowed, *end ) )
1297  {
1298  ++end;
1299  }
1300  // Catch identifiers of the form module::name
1301  if ( end[0] == ':' && end[1] == ':' )
1302  {
1303  end += 2;
1304  while ( *end && !isspace( *end ) && strchr( ident_allowed, *end ) )
1305  {
1306  ++end;
1307  }
1308  }
1309 
1310  int len = static_cast<int>( end - ctx.s + 1 ); // "abcd"
1311 
1312  tok.copyStr( ctx.s, len - 1 );
1313 
1314  tok.id = TOK_IDENT;
1315  tok.type = TYP_OPERAND;
1316 
1317  ctx.s = end;
1318  return 1;
1319  }
1320  return 0;
1321 }
1322 
1323 int Parser::recognize_binary( Token& tok, const char* buf, const char** /*s*/ )
1324 {
1325  for ( int i = 0; i < n_operators; i++ )
1326  {
1327  if ( stricmp( buf, binary_operators[i].code ) == 0 )
1328  {
1329  tok.module = Mod_Basic;
1330  tok.id = binary_operators[i].id;
1331  tok.type = binary_operators[i].type;
1332  tok.precedence = binary_operators[i].precedence;
1333  /*
1334  if (tok.type == TYP_OPERATOR &&
1335  (tok.id == TOK_ADDMEMBER ||
1336  tok.id == TOK_DELMEMBER ||
1337  tok.id == TOK_CHKMEMBER ||
1338  tok.id == TOK_MEMBER) )
1339  {
1340  int res;
1341  Token tk2;
1342  res = getToken( s, tk2 );
1343  if (res < 0) return res;
1344  if (tk2.type != TYP_OPERAND || tk2.id != TOK_IDENT)
1345  return -1;
1346  tok.copyStr( tk2.tokval() );
1347  }
1348  else
1349  {
1350  */
1351  tok.setStr( binary_operators[i].code );
1352  // tok.nulStr();
1353  /*
1354  }
1355  */
1356 
1357  return 1;
1358  }
1359  }
1360  return 0;
1361 }
1362 
1363 int Parser::recognize_unary( Token& tok, const char* buf )
1364 {
1365  for ( int i = 0; i < n_unary; i++ )
1366  {
1367  if ( stricmp( buf, unary_operators[i].code ) == 0 )
1368  {
1369  tok.module = Mod_Basic;
1370  tok.id = unary_operators[i].id;
1371  tok.type = unary_operators[i].type;
1372  tok.precedence = unary_operators[i].precedence;
1373  tok.setStr( unary_operators[i].code );
1374 
1375  return 1;
1376  }
1377  }
1378  return 0;
1379 }
1380 
1381 
1382 int Parser::recognize( Token& tok, const char* buf, const char** s )
1383 {
1384  if ( recognize_binary( tok, buf, s ) )
1385  return 1;
1386  return recognize_unary( tok, buf );
1387 }
1388 
1389 
1390 bool Parser::recognize_reserved_word( Token& tok, const char* buf )
1391 {
1392  if ( tok.id != TOK_IDENT )
1393  return false;
1394 
1395  auto itr = reservedWordsByName.find( buf );
1396  if ( itr != reservedWordsByName.end() )
1397  {
1398  ReservedWord* rv = ( *itr ).second;
1399 
1400  tok.module = Mod_Basic;
1401  tok.id = rv->id;
1402  tok.type = rv->type;
1403  tok.precedence = rv->precedence;
1404  tok.deprecated = rv->deprecated;
1405  tok.setStr( rv->word );
1406  return true;
1407  }
1408  return false;
1409 }
1410 
1411 
1412 /*
1413 int isOperator(Token& token)
1414 {
1415 for(int i=0;i < n_operators; i++) {
1416 if (stricmp(binary_operators[i].code, token )==0) {
1417 token.setStr(binary_operators[i].code);
1418 token.id = binary_operators[i].id;
1419 token.type = binary_operators[i].type;
1420 return 1;
1421 }
1422 }
1423 return 0;
1424 }
1425 */
1426 
1428 {
1429  return static_cast<Precedence>( token.precedence );
1430 }
1431 
1433 {
1434  // qCA.clear();
1435  while ( !ex.CA.empty() )
1436  {
1437  delete ex.CA.front();
1438  ex.CA.pop();
1439  }
1440 
1441  // TX.clear()
1442  while ( !ex.TX.empty() )
1443  {
1444  delete ex.TX.top();
1445  ex.TX.pop();
1446  }
1447 
1448 
1449  err = PERR_NONE;
1450  ext_err[0] = '\0';
1451 }
1452 
1483 int Parser::getToken( CompilerContext& ctx, Token& tok, Expression* /* expr not used */ )
1484 {
1485  int hit = 0;
1486 
1487  int res = ctx.skipcomments();
1488  if ( res )
1489  return res;
1490 
1491  tok.dbg_filenum = ctx.dbg_filenum;
1492  tok.dbg_linenum = ctx.line;
1493 
1494  if ( ctx.s[0] == ';' )
1495  {
1496  tok.module = Mod_Basic;
1497  tok.id = TOK_SEMICOLON;
1498  tok.type = TYP_DELIMITER;
1499  tok.setStr( ";" );
1500  ctx.s++;
1501  return 0;
1502  }
1503 
1504  hit = tryLiteral( tok, ctx );
1505  if ( hit == -1 )
1506  {
1507  return -1;
1508  }
1509  else if ( hit )
1510  {
1511  recognize_reserved_word( tok, tok.tokval() );
1512  return 0;
1513  }
1514 
1515  /*
1516  hit = tryReservedWord(tok, t, s);
1517  if (hit==-1) return -1;
1518  else if (hit) return 0;
1519  */
1520 
1521  hit = tryBinaryOperator( tok, ctx );
1522  if ( hit == -1 )
1523  return -1;
1524  else if ( hit )
1525  return 0;
1526 
1527  hit = tryUnaryOperator( tok, ctx );
1528  if ( hit == -1 )
1529  return -1;
1530  else if ( hit )
1531  return 0;
1532 
1533  // label:
1534  // A:=4;
1535 
1536 
1537  hit = tryNumeric( tok, ctx );
1538  if ( hit == -1 )
1539  return -1;
1540  else if ( hit )
1541  return 0;
1542 
1543  if ( ctx.s[0] == ':' )
1544  {
1545  ++ctx.s;
1546  tok.id = RSV_COLON;
1547  tok.type = TYP_RESERVED;
1548  tok.setStr( ":" );
1549  return 0;
1550  }
1551 
1552  INFO_PRINT << "Your syntax frightens and confuses me.\n";
1553  err = PERR_WAAH;
1554  return -1;
1555 }
1556 
1562 int Parser::peekToken( const CompilerContext& ctx, Token& token, Expression* expr )
1563 {
1564  CompilerContext tctx( ctx );
1565  return getToken( tctx, token, expr );
1566 }
1567 /* Parser::parseToken deleted. */
1568 /* not used? ens 12/10/1998
1569 int Parser::IP(Expression& expr, char *s)
1570 {
1571 reinit(expr);
1572 
1573 Token *ptoken;
1574 if (!quiet) cout << "Parsing \"" << s << '\"' << endl;
1575 
1576 expr.TX.push(new Token); // push terminator token
1577 
1578 ptoken = new Token;
1579 while (getToken(&s, *ptoken)==0)
1580 {
1581 parseToken(expr, ptoken);
1582 ptoken = new Token;
1583 }
1584 parseToken(expr, ptoken);
1585 
1586 return 0;
1587 }
1588 */
1589 
1590 
1591 int SmartParser::isOkay( const Token& token, BTokenType last_type )
1592 {
1593  BTokenType this_type = token.type;
1594  if ( !quiet )
1595  INFO_PRINT << "isOkay(" << this_type << "," << last_type << ")\n";
1596  if ( last_type == TYP_FUNC || last_type == TYP_USERFUNC || last_type == TYP_METHOD ||
1597  last_type == TYP_FUNCREF )
1598  last_type = TYP_OPERAND;
1599  if ( this_type == TYP_FUNC || this_type == TYP_USERFUNC || this_type == TYP_METHOD ||
1600  this_type == TYP_FUNCREF )
1601  this_type = TYP_OPERAND;
1602  if ( token.id == TOK_LBRACE ) // an array declared somewhere out there
1603  this_type = TYP_OPERAND;
1604 
1605  if ( last_type > TYP_TESTMAX )
1606  return 1; // assumed okay
1607  if ( this_type > TYP_TESTMAX )
1608  return 1; // assumed okay
1609  return allowed_table[last_type][this_type]; // maybe okay
1610 }
1611 
1612 /*
1613 int SmartParser::isFunc(Token& token, Verb **v)
1614 {
1615 if (token.id != TOK_IDENT) return 0; // ain't no verb..
1616 // note that this catches string literals.
1617 assert(token.tokval());
1618 
1619 if (isInTable(parser_verbs, n_parser_verbs, token.tokval(), v))
1620 {
1621 token.id = (*v)->id;
1622 token.lval = (*v)->narg;
1623 token.type = TYP_FUNC;
1624 token.module = Mod_Basic;
1625 return 1;
1626 }
1627 return 0;
1628 }
1629 */
1630 
1643 {
1644  int res;
1645  res = Parser::tryLiteral( tok, ctx );
1646  if ( res == 1 && tok.id == TOK_IDENT )
1647  { // check for "label:"
1648 
1649  // whitespace used to be skipped here.
1650  // while (*t && isspace(*t)) t++;
1651  if ( !ctx.s[0] ) // ident EOF can't be a label
1652  {
1653  return 1;
1654  }
1655 
1656 // this might be a nice place to look for module::function, too.
1657 #if 0
1658  if (t[0] == ':' && t[1] == ':')
1659  {
1660  t += 2;
1661  *s = t;
1662  Token tok2;
1663  int res2 = Parser::tryLiteral( tok2, t, s );
1664  if (res2 < 0) return res2;
1665  if (res2 == 0)
1666  return -1;
1667  // append '::{tok2 tokval}' to tok.tokval
1668  // (easier when/if token uses string)
1669  }
1670 #endif
1671  if ( ctx.s[0] == ':' && ( ctx.s[1] == '\0' || isspace( ctx.s[1] ) ) )
1672  {
1673  tok.id = CTRL_LABEL;
1674  tok.type = TYP_LABEL;
1675  ++ctx.s;
1676  }
1677  return 1;
1678  }
1679  return res;
1680 }
1681 
1683 {
1684  // return Parser::parseToken(token);
1685  if ( !quiet )
1686  {
1687  fmt::Writer _tmp;
1688  _tmp << "parseToken( " << *token << ")\n";
1689  _tmp << " CA: ";
1690  std::queue<Token*> ca( expr.CA );
1691  while ( !ca.empty() )
1692  {
1693  Token* tk = ca.front();
1694  _tmp << *tk << " ";
1695  ca.pop();
1696  }
1697  _tmp << "\n";
1698  _tmp << " TX: ";
1699  std::stack<Token*> tx( expr.TX );
1700  while ( !tx.empty() )
1701  {
1702  Token* tk = tx.top();
1703  _tmp << *tk << " ";
1704  tx.pop();
1705  }
1706  INFO_PRINT << _tmp.str() << "\n";
1707  }
1708 
1709  for ( ;; )
1710  {
1711  Token* last = expr.TX.top();
1712  switch ( token->type )
1713  {
1714  case TYP_FUNC:
1715  case TYP_USERFUNC:
1716  case TYP_OPERAND:
1717  expr.CA.push( token );
1718  return 0;
1719  case TYP_TERMINATOR:
1720  switch ( last->type )
1721  {
1722  case TYP_TERMINATOR:
1723  delete token;
1724  delete expr.TX.top();
1725  expr.TX.pop();
1726  return 1; // all done!
1727  case TYP_UNARY_OPERATOR:
1728  expr.CA.push( expr.TX.top() );
1729  expr.TX.pop();
1730  break;
1731  case TYP_OPERATOR:
1732  expr.CA.push( expr.TX.top() );
1733  expr.TX.pop();
1734  break;
1735  case TYP_LEFTPAREN:
1736  err = PERR_MISSRPAREN;
1737  return -1;
1738  case TYP_LEFTBRACKET:
1740  return -1;
1741  default:
1742  err = PERR_WAAH;
1743  return -1;
1744  }
1745  break;
1746  case TYP_UNARY_OPERATOR:
1747  case TYP_OPERATOR:
1748  case TYP_LEFTBRACKET:
1749  // these start out at 0, but need to start at one.
1750  if ( token->type == TYP_LEFTBRACKET )
1751  token->lval = 1;
1752  switch ( last->type )
1753  {
1754  case TYP_TERMINATOR:
1755  case TYP_LEFTPAREN:
1756  case TYP_LEFTBRACKET:
1757  // possible check CA for array dereference operator here.
1758  // if one found, remove it, and change this assignment to a "deref and assign"
1759  expr.TX.push( token );
1760  return 0;
1761  case TYP_UNARY_OPERATOR:
1762  case TYP_OPERATOR:
1763  int this_prec;
1764  int last_prec;
1765 
1766  this_prec = find_precedence( *token );
1767  last_prec = find_precedence( *last );
1768  if ( this_prec > last_prec )
1769  {
1770  expr.TX.push( token );
1771  return 0;
1772  }
1773  else
1774  {
1775  expr.CA.push( expr.TX.top() );
1776  expr.TX.pop();
1777  }
1778  break;
1779  default:
1780  err = PERR_WAAH;
1781  return -1;
1782  break;
1783  }
1784  break;
1785  case TYP_LEFTPAREN:
1786  expr.TX.push( token );
1787  return 0;
1788  case TYP_RIGHTPAREN:
1789  switch ( last->type )
1790  {
1791  case TYP_TERMINATOR:
1792  err = PERR_UNEXRPAREN;
1793  return -1;
1794  case TYP_UNARY_OPERATOR:
1795  case TYP_OPERATOR:
1796  expr.CA.push( expr.TX.top() );
1797  expr.TX.pop();
1798  break;
1799  case TYP_LEFTPAREN:
1800  delete token;
1801  delete expr.TX.top();
1802  expr.TX.pop();
1803  return 0;
1804  default:
1805  INFO_PRINT << "Unmatched ')' in expression. (Trying to match against a '" << *last << "')\n"
1806  << ctx;
1807 
1808  ERROR_PRINT << "parseToken(): Not sure what to do.\n"
1809  << "Token: " << *token << "\n"
1810  << "Last: " << *last << "\n";
1811  throw std::runtime_error( "Error in parseToken() (1)" );
1812  }
1813  break;
1814 
1815  // case TYP_LEFTBRACKET:
1816  // expr.TX.push(token);
1817  // return 0;
1818  case TYP_RIGHTBRACKET:
1819  switch ( last->type )
1820  {
1821  case TYP_TERMINATOR:
1823  return -1;
1824  case TYP_UNARY_OPERATOR:
1825  case TYP_OPERATOR:
1826  expr.CA.push( expr.TX.top() );
1827  expr.TX.pop();
1828  break;
1829  case TYP_LEFTBRACKET:
1830  Token* ptkn;
1831  ptkn = new Token( TOK_ARRAY_SUBSCRIPT, TYP_OPERATOR );
1832  ptkn->lval = last->lval;
1833  ptkn->dbg_filenum = token->dbg_filenum;
1834  ptkn->dbg_linenum = token->dbg_linenum;
1835 
1836  if ( ptkn->lval != 1 )
1837  ptkn->id = INS_MULTISUBSCRIPT;
1838  expr.CA.push( ptkn );
1839 
1840  delete token;
1841  delete expr.TX.top();
1842  expr.TX.pop();
1843  return 0;
1844  default:
1845  INFO_PRINT << "Unmatched ']' in expression. (Trying to match against a '" << *last << "')\n"
1846  << ctx;
1847  ERROR_PRINT << "parseToken(): Not sure what to do.\n"
1848  << "Token: " << *token << "\n"
1849  << "Last: " << *last << "\n";
1850  throw std::runtime_error( "Error in parseToken() (2)" );
1851  }
1852  break;
1853 
1854  /* Special Case: two syntaxes are supported for array indexing:
1855  A[3][4] and A[3,4].
1856  If this is a comma, and we are working in a left bracket area,
1857  increase the number of indices (stored in lval of the leftbracket)
1858  */
1859  case TYP_SEPARATOR:
1860  if ( last->type == TYP_LEFTBRACKET )
1861  {
1862  ++last->lval;
1863  // Token *ptkn = new Token( Mod_Basic, TOK_ARRAY_SUBSCRIPT, TYP_OPERATOR );
1864  // ptkn->lval = last->lval++;
1865  // expr.CA.push( ptkn );
1866 
1867  delete token;
1868  return 0;
1869  }
1870  else if ( last->type == TYP_UNARY_OPERATOR || last->type == TYP_OPERATOR )
1871  {
1872  expr.CA.push( expr.TX.top() );
1873  expr.TX.pop();
1874  break; // try again
1875  }
1876  else
1877  {
1878  err = PERR_UNEXPCOMMA;
1879  return -1;
1880  }
1881 
1882  default:
1883  INFO_PRINT << "Don't know what to do with '" << *token << "' in SmartParser::parseToken\n"
1884  << ctx;
1885  err = PERR_WAAH;
1886  return -1;
1887  }
1888  }
1889 }
1890 
1924 {
1925  int res = Parser::getToken( ctx, token );
1926  if ( res == -1 )
1927  return -1;
1928  if ( token.id == TOK_IDENT )
1929  {
1930  if ( pexpr )
1931  {
1932  if ( !pexpr->TX.empty() )
1933  {
1934  Token* tkn = pexpr->TX.top();
1935  if ( tkn->id == TOK_MEMBER || tkn->id == TOK_ADDMEMBER || tkn->id == TOK_DELMEMBER ||
1936  tkn->id == TOK_CHKMEMBER )
1937  {
1938  token.id = TOK_STRING;
1939  return res;
1940  }
1941  }
1942  }
1943  if ( isFunc( token, &modfunc_ ) )
1944  return 0;
1945  if ( isUserFunc( token, &userfunc_ ) )
1946  return 0;
1947  }
1948  return res;
1949 }
1950 
1951 
1953 {
1954  unsigned nargs = 0;
1955  int res = 0;
1956  ModuleFunction* mfUse = modfunc_;
1957  Token token;
1958  // int nullArgOk = 0;
1959  // int nArgsUse = v->narg;
1960 
1961  /*
1962  if (vUse->narg == -1) {
1963  nullArgOk = 1;
1964  nArgsUse = 1;
1965  }
1966  */
1967 
1968  switch ( mfUse->nargs )
1969  {
1970  case 0: // verb[()];, so INPUT(); or INPUT;
1971  peekToken( ctx, token );
1972  if ( token.id == TOK_LPAREN )
1973  {
1974  getToken( ctx, token );
1975  peekToken( ctx, token );
1976  if ( token.id != TOK_RPAREN )
1977  {
1979  return -1;
1980  }
1981  else
1982  {
1983  getToken( ctx, token );
1984  }
1985  }
1986  break;
1987  case 1: // for one arg, make parens optional.
1988  peekToken( ctx, token );
1989  if ( token.id != TOK_LPAREN )
1990  {
1991  if ( token.id == TOK_SEMICOLON )
1992  {
1993  // if (nullArgOk) return 0;
1994  err = PERR_TOOFEWARGS;
1995  return -1;
1996  }
1998  break;
1999  }
2000  // if left paren specified
2001  // FALLTHROUGH
2002  default:
2003  // for more than one arg, or voluntary left paren on single
2004  // arg, so parens are required
2005  // grab the opening parenthesis
2006  getToken( ctx, token );
2007  if ( token.id != TOK_LPAREN )
2008  {
2009  res = -1;
2010  err = PERR_MISSLPAREN;
2011  return -1;
2012  }
2013  for ( nargs = 0; nargs < mfUse->nargs; nargs++ )
2014  {
2015  if ( nargs ) // grab the comma.
2016  {
2017  getToken( ctx, token );
2018  if ( token.id != TOK_COMMA )
2019  {
2020  // if (nullArgOk) break;
2021  res = -1;
2022  err = PERR_TOOFEWARGS;
2023  break;
2024  }
2025  }
2027  if ( res < 0 )
2028  break;
2029  err = PERR_NONE;
2030  }
2031  if ( nargs != mfUse->nargs )
2032  {
2033  err = PERR_TOOFEWARGS;
2034  return -1;
2035  ;
2036  }
2037  // get the right paren.
2038  getToken( ctx, token );
2039  if ( token.id != TOK_RPAREN )
2040  {
2042  res = -1;
2043  }
2044 
2045  break;
2046  }
2047 
2048  // now have parsed the arguments and parenthesis.
2049  // leave the delimiter ';', it will be picked up later, or
2050  // may not be there (i.e. MID(A,5) + A; )
2051  return res;
2052 }
2053 
2055 {
2056  // if we have something like x.foo(), change to call-method
2057  CompilerContext tctx( ctx );
2058  Token tk_name, tk_paren;
2059 
2060  if ( getToken( tctx, tk_name ) == 0 && getToken( tctx, tk_paren ) == 0 &&
2061  ( tk_name.id == TOK_IDENT || tk_name.id == TOK_FUNC || tk_name.id == TOK_USERFUNC ) &&
2062  tk_paren.id == TOK_LPAREN )
2063  {
2064  return true;
2065  }
2066  return false;
2067 }
2068 
2077 int SmartParser::IIP( Expression& expr, CompilerContext& ctx, unsigned flags )
2078 {
2079  BTokenType last_type = TYP_TERMINATOR;
2080  Token last_token;
2081  // Token* debug_last_tx_token = NULL;
2082  int done = 0;
2083  int res = 0; // 1=done, -1=error, 0=not done
2084 
2085  int semicolon_term_allowed = flags & EXPR_FLAG_SEMICOLON_TERM_ALLOWED;
2086  int comma_term_allowed = flags & EXPR_FLAG_COMMA_TERM_ALLOWED;
2087  int rightparen_term_allowed = flags & EXPR_FLAG_RIGHTPAREN_TERM_ALLOWED;
2088  int rightbrace_term_allowed = flags & EXPR_FLAG_RIGHTBRACE_TERM_ALLOWED;
2089  int dictkey_term_allowed = flags & EXPR_FLAG_DICTKEY_TERM_ALLOWED;
2090  int endenum_term_allowed = flags & EXPR_FLAG_ENDENUM_TERM_ALLOWED;
2091  int to_term_allowed = flags & EXPR_FLAG_TO_TERM_ALLOWED;
2092  int auto_term_allowed = flags & EXPR_FLAG_AUTO_TERM_ALLOWED;
2093  if ( !quiet )
2094  {
2095  char buf[80];
2096  Clib::stracpy( buf, ctx.s, 80 );
2097  strtok( buf, "\r\n" );
2098  INFO_PRINT << "Parsing " << buf << "\n";
2099  }
2100 
2101  expr.TX.push( new Token ); /* push a terminator token */
2102  int leftbracket_count = 0;
2103  while ( !done && ( res == 0 ) )
2104  {
2105  const char* t = ctx.s;
2106  Token token;
2107 
2108  res = peekToken( ctx, token );
2109 
2110  if ( res )
2111  break;
2112  if ( !isLegal( token ) )
2113  {
2115  res = -1;
2116  break;
2117  }
2118 
2119  // if (token.type == TYP_DELIMITER) break;
2120  // debug_last_tx_token = expr.TX.top();
2121 
2122  /*
2123  if (comma_term_allowed)
2124  {
2125  Token* tkn = expr.TX.top();
2126  if (leftbracket_count > 0) // tkn != NULL && tkn->id == TOK_LBRACKET )
2127  {
2128  // ignore commas if we're in a left bracket situation.
2129  ;
2130  }
2131  else if (token.id == TOK_COMMA || token.id == TOK_SEMICOLON)
2132  {
2133  break;
2134  }
2135  }
2136  */
2137  if ( leftbracket_count == 0 )
2138  {
2139  if ( comma_term_allowed && ( token.id == TOK_COMMA || token.id == TOK_SEMICOLON ) )
2140  {
2141  break;
2142  }
2143  if ( endenum_term_allowed && ( token.id == RSV_ENDENUM ) )
2144  {
2145  break;
2146  }
2147  if ( to_term_allowed && ( token.id == RSV_TO ) )
2148  {
2149  break;
2150  }
2151  }
2152 
2153  if ( rightbrace_term_allowed && token.id == TOK_RBRACE )
2154  {
2155  break;
2156  }
2157  if ( dictkey_term_allowed && token.id == TOK_DICTKEY )
2158  {
2159  break;
2160  }
2161 
2162  /*
2163  else
2164  {
2165  if (token.type == TYP_SEPARATOR)
2166  {
2167  err = PERR_UNEXPCOMMA;
2168  res = -1;
2169  break;
2170  }
2171  }
2172  */
2173 
2174  // auto-terminated expressions need to not eat what broke them out...
2175  CompilerContext save_ctx( ctx );
2176 
2177  res = getToken( ctx, token, &expr );
2178 
2179  if ( semicolon_term_allowed && token.id == TOK_SEMICOLON )
2180  break;
2181 
2182  if ( token.id == TOK_LBRACKET )
2183  ++leftbracket_count;
2184  else if ( token.id == TOK_RBRACKET )
2185  --leftbracket_count;
2186 
2187  if ( !isOkay( token, last_type ) )
2188  {
2189  if ( token.type == TYP_OPERATOR ) // check for a unary operator that looks the same.
2190  recognize_unary( token, token.tokval() );
2191 
2192  if ( !isOkay( token, last_type ) )
2193  {
2194  if ( auto_term_allowed )
2195  {
2196  ctx = save_ctx;
2197  break;
2198  }
2199 
2200  res = -1;
2202  ctx.s = t; // FIXME operator=
2203  INFO_PRINT << "Token '" << token << "' cannot follow token '" << last_token << "'\n";
2204  if ( last_token.type == TYP_OPERAND && token.id == TOK_LPAREN )
2205  {
2206  INFO_PRINT << "Function " << last_token << "() is not defined.\n";
2207  }
2208  break;
2209  }
2210  }
2211  else if ( last_type == TYP_TERMINATOR && token.type == TYP_LEFTBRACE &&
2214  {
2215  INFO_PRINT
2216  << "Warning: Using { } is inappropriate; please define array, struct or dictionary.\n";
2218  throw std::runtime_error( "Warnings treated as errors." );
2219  else
2220  INFO_PRINT << ctx;
2221  }
2222  last_type = token.type;
2223  last_token = token;
2224 
2225  //
2226  // only certain types of things can be in an auto-terminated expr
2227  // stuff like 'var' and statements can't.
2228  //
2229  if ( auto_term_allowed )
2230  {
2231  if ( token.type != TYP_FUNC && token.type != TYP_USERFUNC && token.type != TYP_OPERAND &&
2232  token.type != TYP_UNARY_OPERATOR && token.type != TYP_OPERATOR &&
2233  token.type != TYP_LEFTPAREN && token.type != TYP_RIGHTPAREN &&
2234  token.type != TYP_LEFTBRACKET && token.type != TYP_RIGHTBRACKET &&
2235  token.type != TYP_SEPARATOR && token.id != TOK_LBRACE && token.id != TOK_RBRACE )
2236  {
2237  ctx = save_ctx;
2238  break;
2239  }
2240  }
2241 
2242  Token* ptok2;
2243  if ( token.type == TYP_USERFUNC )
2244  {
2245  res = getUserArgs( expr, ctx );
2246  if ( res < 0 )
2247  return res;
2248 
2249  ptok2 = new Token( token );
2250  res = parseToken( ctx, expr, ptok2 );
2251  if ( res < 0 )
2252  {
2253  delete ptok2;
2254  ctx.s = t;
2255  }
2256  }
2257  else if ( token.type == TYP_FUNC )
2258  {
2259  userfunc_ = modfunc_->uf;
2260  res = getUserArgs( expr, ctx, false );
2261  if ( res < 0 )
2262  {
2263  INFO_PRINT << "Error getting arguments for function " << token.tokval() << "\n"
2264  << ctx << "\n";
2265  return res;
2266  }
2267  ptok2 = new Token( token );
2268  res = parseToken( ctx, expr, ptok2 );
2269  if ( res < 0 )
2270  {
2271  delete ptok2;
2272  ctx.s = t; // FIXME operator=
2273 
2274  if ( ( err == PERR_UNEXRPAREN ) && rightparen_term_allowed )
2275  {
2276  err = PERR_NONE;
2277  res = 0;
2278  done = 1;
2279  }
2280  }
2281  }
2282  else if ( token.id == TOK_ARRAY )
2283  {
2284  auto array_tkn = new Token( TOK_ARRAY, TYP_OPERAND );
2285  array_tkn->dbg_filenum = token.dbg_filenum;
2286  array_tkn->dbg_linenum = token.dbg_linenum;
2287 
2288  res = parseToken( ctx, expr, array_tkn );
2289  if ( res < 0 )
2290  return res;
2291 
2292  // expr.CA.push( array_tkn );
2293 
2294  // 'array' can be of the following forms:
2295  // var x := array; // preferred
2296  // var x := array { 2, 4, 6, 1 }; // preferred
2297  // var x := array ( 2, 4, 6, 1 ); // not preferred, looks too much like a multi-dim
2298 
2299  Token peek_token;
2300  res = peekToken( ctx, peek_token );
2301  if ( res == 0 )
2302  {
2303  if ( peek_token.id == TOK_LPAREN )
2304  {
2305  res = getArrayElements( expr, ctx );
2306  }
2307  else if ( peek_token.id == TOK_LBRACE )
2308  {
2309  // this form expects that the LBRACE has been eaten, so do so.
2310  getToken( ctx, peek_token );
2311  res = getNewArrayElements( expr, ctx );
2312  }
2313  if ( res < 0 )
2314  {
2315  INFO_PRINT << "Error getting elements for array\n";
2316  }
2317  }
2318  }
2319  else if ( token.id == TOK_LBRACE ) // a bare array declaration, like var x := { 2, 4 };
2320  {
2321  expr.CA.push( new Token( TOK_ARRAY, TYP_OPERAND ) );
2322  res = getNewArrayElements( expr, ctx );
2323  if ( res < 0 )
2324  {
2325  INFO_PRINT << "Error getting elements for array\n";
2326  }
2327  }
2328  else if ( token.id == TOK_ERROR )
2329  {
2330  auto error_tkn = new Token( TOK_ERROR, TYP_OPERAND );
2331  error_tkn->dbg_filenum = token.dbg_filenum;
2332  error_tkn->dbg_linenum = token.dbg_linenum;
2333  expr.CA.push( error_tkn );
2334  res = getStructMembers( expr, ctx );
2335  if ( res < 0 )
2336  {
2337  INFO_PRINT << "Error reading members for error\n";
2338  }
2339  }
2340  else if ( token.id == TOK_STRUCT )
2341  {
2342  auto struct_tkn = new Token( TOK_STRUCT, TYP_OPERAND );
2343  struct_tkn->dbg_filenum = token.dbg_filenum;
2344  struct_tkn->dbg_linenum = token.dbg_linenum;
2345  expr.CA.push( struct_tkn );
2346  res = getStructMembers( expr, ctx );
2347  if ( res < 0 )
2348  {
2349  INFO_PRINT << "Error reading members for struct\n";
2350  }
2351  }
2352  else if ( token.id == TOK_DICTIONARY )
2353  {
2354  auto dict_tkn = new Token( token ); // Mod_Basic, TOK_DICTIONARY, TYP_OPERAND );
2355  // struct_tkn->dbg_filenum = token.dbg_filenum;
2356  // struct_tkn->dbg_linenum = token.dbg_linenum;
2357  expr.CA.push( dict_tkn );
2358  res = getDictionaryMembers( expr, ctx );
2359  if ( res < 0 )
2360  {
2361  INFO_PRINT << "Error reading members for dictionary\n";
2362  }
2363  }
2364  else if ( token.id == TOK_FUNCREF )
2365  {
2366  auto ref_tkn = new Token( token );
2367  res = getFunctionPArgument( expr, ctx, ref_tkn );
2368  if ( res < 0 )
2369  {
2370  INFO_PRINT << "Error reading function reference argument\n";
2371  }
2372  expr.CA.push( ref_tkn );
2373  }
2374  else if ( token.id == TOK_MEMBER && callingMethod( ctx ) )
2375  {
2376  // look for something like x.foo(b);
2377  // we'll catch this on the 'foo'
2378  // so check for preceding TOK_MEMBER, and succeeding TOK_LPAREN
2379 
2380  ptok2 = new Token( token ); // this we will turn into an INS_CALL_METHOD.
2381  int _res = parseToken( ctx, expr, ptok2 );
2382  if ( _res < 0 )
2383  {
2384  delete ptok2;
2385  return _res;
2386  }
2387 
2388  // grab the method name
2389  getToken( ctx, token, &expr );
2390  std::string methodName( token.tokval() );
2391  Clib::mklower( methodName );
2392  int nargs;
2393  res = getMethodArguments( expr, ctx, nargs );
2394  // our ptok2 is now sitting in TX. Move it to CA.
2395  Token* _t = expr.TX.top();
2396  expr.TX.pop();
2397  expr.CA.push( _t );
2398 
2399  ObjMethod* objmeth = getKnownObjMethod( methodName.c_str() );
2400  if ( objmeth != NULL && compilercfg.OptimizeObjectMembers )
2401  {
2402  ptok2->id = INS_CALL_METHOD_ID;
2403  ptok2->type = TYP_METHOD;
2404  ptok2->lval = nargs;
2405  ptok2->dval = objmeth->id;
2406  }
2407  else
2408  {
2409  ptok2->id = INS_CALL_METHOD;
2410  ptok2->type = TYP_METHOD;
2411  ptok2->lval = nargs;
2412  ptok2->copyStr( methodName.c_str() );
2413  }
2414  last_type = TYP_OPERAND;
2415  }
2416  else
2417  {
2418  if ( res >= 0 )
2419  {
2420  ptok2 = new Token( token );
2421  res = parseToken( ctx, expr, ptok2 );
2422  if ( res < 0 )
2423  {
2424  delete ptok2;
2425  ctx.s = t; // FIXME operator=
2426 
2427  if ( ( err == PERR_UNEXRPAREN ) && rightparen_term_allowed )
2428  {
2429  err = PERR_NONE;
2430  res = 0;
2431  done = 1;
2432  }
2433  }
2434  }
2435  }
2436  if ( flags & EXPR_FLAG_SINGLE_ELEMENT )
2437  done = 1;
2438  }
2439 
2440  int nres = parseToken( ctx, expr, new Token ); /* end of expression */
2441  if ( res >= 0 )
2442  res = nres;
2443 
2444  if ( !comma_term_allowed && !quiet )
2445  {
2446  INFO_PRINT << "Result: " << res << "\n";
2447  }
2448  return res;
2449 }
2450 
2451 /* not used? 12/10/1998 ens
2452 int SmartParser::IP(Expression& expr, char *s)
2453 {
2454 // return Parser::IP(s);
2455 reinit(expr);
2456 int res = IIP(expr, &s, EXPR_FLAG_SEMICOLON_TERM_ALLOWED);
2457 if (res < 0 && !quiet)
2458 {
2459 cout << "Parse Error: " << ParseErrorStr[err];
2460 if (ext_err[0]) cout << " " << ext_err;
2461 cout << endl;
2462 }
2463 return res;
2464 }
2465 */
2466 
2468 {
2469  reinit( expr );
2470  return IIP( expr, ctx, EXPR_FLAG_SEMICOLON_TERM_ALLOWED );
2471 }
2472 }
2473 }
unsigned char u8
Definition: rawtypes.h:25
virtual int tryBinaryOperator(Token &tok, CompilerContext &ctx)
Definition: parser.cpp:1123
const unsigned EXPR_FLAG_DICTKEY_TERM_ALLOWED
Definition: parser.h:104
virtual int recognize(Token &tok, const char *buf, const char **s)
Definition: parser.cpp:1382
const unsigned EXPR_FLAG_AUTO_TERM_ALLOWED
Definition: parser.h:102
static void write_words(std::ostream &os)
Definition: parser.cpp:926
std::queue< Token * > CA
Definition: parser.h:91
virtual bool recognize_reserved_word(Token &tok, const char *buf)
Definition: parser.cpp:1390
virtual int getToken(CompilerContext &ctx, Token &token, Expression *expr=NULL) POL_OVERRIDE
Definition: parser.cpp:1923
int getArgs(Expression &expr, CompilerContext &ctx)
Definition: parser.cpp:1952
ReservedWord reserved_words[]
Definition: parser.cpp:810
BTokenType type
Definition: token.h:40
char ext_err[50]
Definition: parser.h:116
virtual int tryOperator(Token &tok, const char *buf, const char **s, Operator *opList, int n_ops, char *opbuf)
Definition: parser.cpp:1048
std::stack< Token * > TX
Definition: parser.h:90
ParseError err
Definition: parser.h:114
const char * tokval() const
Definition: token.h:71
void reinit(Expression &ex)
Definition: parser.cpp:1432
ObjMember * getKnownObjMember(const char *token)
Definition: parser.cpp:483
BTokenId id
Definition: token.h:39
int IP(Expression &expr, char *s)
Operator binary_operators[]
Definition: parser.cpp:189
std::map< std::string, ReservedWord *, Clib::ci_cmp_pred > ReservedWords
Definition: parser.cpp:913
unsigned n_reserved
Definition: parser.cpp:911
const unsigned EXPR_FLAG_SINGLE_ELEMENT
Definition: parser.h:98
char buffer[51]
Definition: parser.h:117
virtual int recognize_binary(Token &tok, const char *buf, const char **s)
Definition: parser.cpp:1323
char * stracpy(char *dest, const char *src, size_t maxlen)
Definition: stracpy.cpp:17
int n_objmembers
Definition: parser.cpp:482
int allowed_table[8][8]
Definition: parser.cpp:111
CompilerConfig compilercfg
ObjMethod * getKnownObjMethod(const char *token)
Definition: parser.cpp:666
const unsigned EXPR_FLAG_RIGHTPAREN_TERM_ALLOWED
Definition: parser.h:97
virtual int recognize_unary(Token &tok, const char *buf)
Definition: parser.cpp:1363
char ident_allowed[]
Definition: parser.cpp:104
int IIP(Expression &expr, CompilerContext &ctx, unsigned expr_flags)
Definition: parser.cpp:2077
void copyStr(const char *s)
Definition: token.cpp:214
const unsigned EXPR_FLAG_TO_TERM_ALLOWED
Definition: parser.h:101
virtual int parseToken(CompilerContext &ctx, Expression &expr, Token *) POL_OVERRIDE
Definition: parser.cpp:1682
Clib::UnitTest testparserdefinitions_obj(testparserdefinitions)
int n_operators
Definition: parser.cpp:243
void matchOperators(Operator *oplist, int n_ops, char *buf, int *nPartial, Operator **pTotalMatchOperator)
Definition: parser.cpp:736
virtual int tryNumeric(Token &tok, CompilerContext &ctx)
Definition: parser.cpp:1157
virtual int getToken(CompilerContext &ctx, Token &token, Expression *expr=NULL)
Definition: parser.cpp:1483
ObjMember * getObjMember(int id)
Definition: parser.cpp:501
ObjMethod * getObjMethod(int id)
Definition: parser.cpp:685
virtual int tryLiteral(Token &tok, CompilerContext &ctx)
Definition: parser.cpp:1215
void testparserdefinitions()
Definition: parser.cpp:693
Precedence precedence
Definition: operator.h:41
#define passert_always_r(exp, reason)
Definition: passert.h:84
virtual int tryUnaryOperator(Token &tok, CompilerContext &ctx)
Definition: parser.cpp:1140
const char * ParseErrorStr[PERR_NUM_ERRORS]
Definition: parser.cpp:82
char operator_brk[]
Definition: parser.cpp:102
const unsigned EXPR_FLAG_RIGHTBRACE_TERM_ALLOWED
Definition: parser.h:100
ReservedWords reservedWordsByName
Definition: parser.cpp:914
virtual int peekToken(const CompilerContext &ctx, Token &token, Expression *expr=NULL)
Definition: parser.cpp:1562
virtual int tryLiteral(Token &tok, CompilerContext &ctx) POL_OVERRIDE
Definition: parser.cpp:1642
virtual int parseToken(CompilerContext &ctx, Expression &expr, Token *token)=0
unsigned char module
Definition: token.h:55
#define ERROR_PRINT
Definition: logfacility.h:230
void setStr(const char *s)
Definition: token.cpp:204
const unsigned EXPR_FLAG_COMMA_TERM_ALLOWED
Definition: parser.h:96
void mklower(std::string &str)
Definition: strutil.cpp:266
Precedence find_precedence(Token &token)
Definition: parser.cpp:1427
#define INFO_PRINT
Definition: logfacility.h:223
int n_objmethods
Definition: parser.cpp:665
bool callingMethod(CompilerContext &ctx)
Definition: parser.cpp:2054
Definition: berror.cpp:12
ObjMethod object_methods[]
Definition: parser.cpp:509
virtual int isOkay(const Token &token, BTokenType last_type)
Definition: parser.cpp:1591
const unsigned EXPR_FLAG_ENDENUM_TERM_ALLOWED
Definition: parser.h:99
ObjMember object_members[]
Definition: parser.cpp:256
static void init_tables()
Definition: parser.cpp:915
Operator unary_operators[]
Definition: parser.cpp:245
const unsigned EXPR_FLAG_SEMICOLON_TERM_ALLOWED
Definition: parser.h:95