PR_LEX.C 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. #include "qcc.h"
  2. int pr_source_line;
  3. char *pr_file_p;
  4. char *pr_line_start; // start of current source line
  5. int pr_bracelevel;
  6. char pr_token[2048];
  7. token_type_t pr_token_type;
  8. type_t *pr_immediate_type;
  9. eval_t pr_immediate;
  10. char pr_immediate_string[2048];
  11. int pr_error_count;
  12. char *pr_punctuation[] =
  13. // longer symbols must be before a shorter partial match
  14. {"&&", "||", "<=", ">=","==", "!=", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", ".", "<", ">" , "#" , "&" , "|" , NULL};
  15. // simple types. function types are dynamically allocated
  16. type_t type_void = {ev_void, &def_void};
  17. type_t type_string = {ev_string, &def_string};
  18. type_t type_float = {ev_float, &def_float};
  19. type_t type_vector = {ev_vector, &def_vector};
  20. type_t type_entity = {ev_entity, &def_entity};
  21. type_t type_field = {ev_field, &def_field};
  22. type_t type_function = {ev_function, &def_function,NULL,&type_void};
  23. // type_function is a void() function used for state defs
  24. type_t type_pointer = {ev_pointer, &def_pointer};
  25. type_t type_floatfield = {ev_field, &def_field, NULL, &type_float};
  26. int type_size[8] = {1,1,1,3,1,1,1,1};
  27. def_t def_void = {&type_void, "temp"};
  28. def_t def_string = {&type_string, "temp"};
  29. def_t def_float = {&type_float, "temp"};
  30. def_t def_vector = {&type_vector, "temp"};
  31. def_t def_entity = {&type_entity, "temp"};
  32. def_t def_field = {&type_field, "temp"};
  33. def_t def_function = {&type_function, "temp"};
  34. def_t def_pointer = {&type_pointer, "temp"};
  35. def_t def_ret, def_parms[MAX_PARMS];
  36. def_t *def_for_type[8] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer};
  37. void PR_LexWhitespace (void);
  38. /*
  39. ==============
  40. PR_PrintNextLine
  41. ==============
  42. */
  43. void PR_PrintNextLine (void)
  44. {
  45. char *t;
  46. printf ("%3i:",pr_source_line);
  47. for (t=pr_line_start ; *t && *t != '\n' ; t++)
  48. printf ("%c",*t);
  49. printf ("\n");
  50. }
  51. /*
  52. ==============
  53. PR_NewLine
  54. Call at start of file and when *pr_file_p == '\n'
  55. ==============
  56. */
  57. void PR_NewLine (void)
  58. {
  59. qboolean m;
  60. if (*pr_file_p == '\n')
  61. {
  62. pr_file_p++;
  63. m = true;
  64. }
  65. else
  66. m = false;
  67. pr_source_line++;
  68. pr_line_start = pr_file_p;
  69. // if (pr_dumpasm)
  70. // PR_PrintNextLine ();
  71. if (m)
  72. pr_file_p--;
  73. }
  74. /*
  75. ==============
  76. PR_LexString
  77. Parses a quoted string
  78. ==============
  79. */
  80. void PR_LexString (void)
  81. {
  82. int c;
  83. int len;
  84. len = 0;
  85. pr_file_p++;
  86. do
  87. {
  88. c = *pr_file_p++;
  89. if (!c)
  90. PR_ParseError ("EOF inside quote");
  91. if (c=='\n')
  92. PR_ParseError ("newline inside quote");
  93. if (c=='\\')
  94. { // escape char
  95. c = *pr_file_p++;
  96. if (!c)
  97. PR_ParseError ("EOF inside quote");
  98. if (c == 'n')
  99. c = '\n';
  100. else if (c == '"')
  101. c = '"';
  102. else
  103. PR_ParseError ("Unknown escape char");
  104. }
  105. else if (c=='\"')
  106. {
  107. pr_token[len] = 0;
  108. pr_token_type = tt_immediate;
  109. pr_immediate_type = &type_string;
  110. strcpy (pr_immediate_string, pr_token);
  111. return;
  112. }
  113. pr_token[len] = c;
  114. len++;
  115. } while (1);
  116. }
  117. /*
  118. ==============
  119. PR_LexNumber
  120. ==============
  121. */
  122. float PR_LexNumber (void)
  123. {
  124. int c;
  125. int len;
  126. len = 0;
  127. c = *pr_file_p;
  128. do
  129. {
  130. pr_token[len] = c;
  131. len++;
  132. pr_file_p++;
  133. c = *pr_file_p;
  134. } while ((c >= '0' && c<= '9') || c == '.');
  135. pr_token[len] = 0;
  136. return atof (pr_token);
  137. }
  138. /*
  139. ==============
  140. PR_LexVector
  141. Parses a single quoted vector
  142. ==============
  143. */
  144. void PR_LexVector (void)
  145. {
  146. int i;
  147. pr_file_p++;
  148. pr_token_type = tt_immediate;
  149. pr_immediate_type = &type_vector;
  150. for (i=0 ; i<3 ; i++)
  151. {
  152. pr_immediate.vector[i] = PR_LexNumber ();
  153. PR_LexWhitespace ();
  154. }
  155. if (*pr_file_p != '\'')
  156. PR_ParseError ("Bad vector");
  157. pr_file_p++;
  158. }
  159. /*
  160. ==============
  161. PR_LexName
  162. Parses an identifier
  163. ==============
  164. */
  165. void PR_LexName (void)
  166. {
  167. int c;
  168. int len;
  169. len = 0;
  170. c = *pr_file_p;
  171. do
  172. {
  173. pr_token[len] = c;
  174. len++;
  175. pr_file_p++;
  176. c = *pr_file_p;
  177. } while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
  178. || (c >= '0' && c <= '9'));
  179. pr_token[len] = 0;
  180. pr_token_type = tt_name;
  181. }
  182. /*
  183. ==============
  184. PR_LexPunctuation
  185. ==============
  186. */
  187. void PR_LexPunctuation (void)
  188. {
  189. int i;
  190. int len;
  191. char *p;
  192. pr_token_type = tt_punct;
  193. for (i=0 ; (p = pr_punctuation[i]) != NULL ; i++)
  194. {
  195. len = strlen(p);
  196. if (!strncmp(p, pr_file_p, len) )
  197. {
  198. strcpy (pr_token, p);
  199. if (p[0] == '{')
  200. pr_bracelevel++;
  201. else if (p[0] == '}')
  202. pr_bracelevel--;
  203. pr_file_p += len;
  204. return;
  205. }
  206. }
  207. PR_ParseError ("Unknown punctuation");
  208. }
  209. /*
  210. ==============
  211. PR_LexWhitespace
  212. ==============
  213. */
  214. void PR_LexWhitespace (void)
  215. {
  216. int c;
  217. while (1)
  218. {
  219. // skip whitespace
  220. while ( (c = *pr_file_p) <= ' ')
  221. {
  222. if (c=='\n')
  223. PR_NewLine ();
  224. if (c == 0)
  225. return; // end of file
  226. pr_file_p++;
  227. }
  228. // skip // comments
  229. if (c=='/' && pr_file_p[1] == '/')
  230. {
  231. while (*pr_file_p && *pr_file_p != '\n')
  232. pr_file_p++;
  233. PR_NewLine();
  234. pr_file_p++;
  235. continue;
  236. }
  237. // skip /* */ comments
  238. if (c=='/' && pr_file_p[1] == '*')
  239. {
  240. do
  241. {
  242. pr_file_p++;
  243. if (pr_file_p[0]=='\n')
  244. PR_NewLine();
  245. if (pr_file_p[1] == 0)
  246. return;
  247. } while (pr_file_p[-1] != '*' || pr_file_p[0] != '/');
  248. pr_file_p++;
  249. continue;
  250. }
  251. break; // a real character has been found
  252. }
  253. }
  254. //============================================================================
  255. #define MAX_FRAMES 256
  256. char pr_framemacros[MAX_FRAMES][16];
  257. int pr_nummacros;
  258. void PR_ClearGrabMacros (void)
  259. {
  260. pr_nummacros = 0;
  261. }
  262. void PR_FindMacro (void)
  263. {
  264. int i;
  265. for (i=0 ; i<pr_nummacros ; i++)
  266. if (!strcmp (pr_token, pr_framemacros[i]))
  267. {
  268. sprintf (pr_token,"%d", i);
  269. pr_token_type = tt_immediate;
  270. pr_immediate_type = &type_float;
  271. pr_immediate._float = i;
  272. return;
  273. }
  274. PR_ParseError ("Unknown frame macro $%s", pr_token);
  275. }
  276. // just parses text, returning false if an eol is reached
  277. qboolean PR_SimpleGetToken (void)
  278. {
  279. int c;
  280. int i;
  281. // skip whitespace
  282. while ( (c = *pr_file_p) <= ' ')
  283. {
  284. if (c=='\n' || c == 0)
  285. return false;
  286. pr_file_p++;
  287. }
  288. i = 0;
  289. while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';')
  290. {
  291. pr_token[i] = c;
  292. i++;
  293. pr_file_p++;
  294. }
  295. pr_token[i] = 0;
  296. return true;
  297. }
  298. void PR_ParseFrame (void)
  299. {
  300. while (PR_SimpleGetToken ())
  301. {
  302. strcpy (pr_framemacros[pr_nummacros], pr_token);
  303. pr_nummacros++;
  304. }
  305. }
  306. /*
  307. ==============
  308. PR_LexGrab
  309. Deals with counting sequence numbers and replacing frame macros
  310. ==============
  311. */
  312. void PR_LexGrab (void)
  313. {
  314. pr_file_p++; // skip the $
  315. if (!PR_SimpleGetToken ())
  316. PR_ParseError ("hanging $");
  317. // check for $frame
  318. if (!strcmp (pr_token, "frame"))
  319. {
  320. PR_ParseFrame ();
  321. PR_Lex ();
  322. }
  323. // ignore other known $commands
  324. else if (!strcmp (pr_token, "cd")
  325. || !strcmp (pr_token, "origin")
  326. || !strcmp (pr_token, "base")
  327. || !strcmp (pr_token, "flags")
  328. || !strcmp (pr_token, "scale")
  329. || !strcmp (pr_token, "skin") )
  330. { // skip to end of line
  331. while (PR_SimpleGetToken ())
  332. ;
  333. PR_Lex ();
  334. }
  335. // look for a frame name macro
  336. else
  337. PR_FindMacro ();
  338. }
  339. //============================================================================
  340. /*
  341. ==============
  342. PR_Lex
  343. Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
  344. ==============
  345. */
  346. void PR_Lex (void)
  347. {
  348. int c;
  349. pr_token[0] = 0;
  350. if (!pr_file_p)
  351. {
  352. pr_token_type = tt_eof;
  353. return;
  354. }
  355. PR_LexWhitespace ();
  356. c = *pr_file_p;
  357. if (!c)
  358. {
  359. pr_token_type = tt_eof;
  360. return;
  361. }
  362. // handle quoted strings as a unit
  363. if (c == '\"')
  364. {
  365. PR_LexString ();
  366. return;
  367. }
  368. // handle quoted vectors as a unit
  369. if (c == '\'')
  370. {
  371. PR_LexVector ();
  372. return;
  373. }
  374. // if the first character is a valid identifier, parse until a non-id
  375. // character is reached
  376. if ( (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') )
  377. {
  378. pr_token_type = tt_immediate;
  379. pr_immediate_type = &type_float;
  380. pr_immediate._float = PR_LexNumber ();
  381. return;
  382. }
  383. if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
  384. {
  385. PR_LexName ();
  386. return;
  387. }
  388. if (c == '$')
  389. {
  390. PR_LexGrab ();
  391. return;
  392. }
  393. // parse symbol strings until a non-symbol is found
  394. PR_LexPunctuation ();
  395. }
  396. //=============================================================================
  397. /*
  398. ============
  399. PR_ParseError
  400. Aborts the current file load
  401. ============
  402. */
  403. void PR_ParseError (char *error, ...)
  404. {
  405. va_list argptr;
  406. char string[1024];
  407. va_start (argptr,error);
  408. vsprintf (string,error,argptr);
  409. va_end (argptr);
  410. printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string);
  411. longjmp (pr_parse_abort, 1);
  412. }
  413. /*
  414. =============
  415. PR_Expect
  416. Issues an error if the current token isn't equal to string
  417. Gets the next token
  418. =============
  419. */
  420. void PR_Expect (char *string)
  421. {
  422. if (strcmp (string, pr_token))
  423. PR_ParseError ("expected %s, found %s",string, pr_token);
  424. PR_Lex ();
  425. }
  426. /*
  427. =============
  428. PR_Check
  429. Returns true and gets the next token if the current token equals string
  430. Returns false and does nothing otherwise
  431. =============
  432. */
  433. qboolean PR_Check (char *string)
  434. {
  435. if (strcmp (string, pr_token))
  436. return false;
  437. PR_Lex ();
  438. return true;
  439. }
  440. /*
  441. ============
  442. PR_ParseName
  443. Checks to see if the current token is a valid name
  444. ============
  445. */
  446. char *PR_ParseName (void)
  447. {
  448. static char ident[MAX_NAME];
  449. if (pr_token_type != tt_name)
  450. PR_ParseError ("not a name");
  451. if (strlen(pr_token) >= MAX_NAME-1)
  452. PR_ParseError ("name too long");
  453. strcpy (ident, pr_token);
  454. PR_Lex ();
  455. return ident;
  456. }
  457. /*
  458. ============
  459. PR_FindType
  460. Returns a preexisting complex type that matches the parm, or allocates
  461. a new one and copies it out.
  462. ============
  463. */
  464. type_t *PR_FindType (type_t *type)
  465. {
  466. def_t *def;
  467. type_t *check;
  468. int i;
  469. for (check = pr.types ; check ; check = check->next)
  470. {
  471. if (check->type != type->type
  472. || check->aux_type != type->aux_type
  473. || check->num_parms != type->num_parms)
  474. continue;
  475. for (i=0 ; i< type->num_parms ; i++)
  476. if (check->parm_types[i] != type->parm_types[i])
  477. break;
  478. if (i == type->num_parms)
  479. return check;
  480. }
  481. // allocate a new one
  482. check = malloc (sizeof (*check));
  483. *check = *type;
  484. check->next = pr.types;
  485. pr.types = check;
  486. // allocate a generic def for the type, so fields can reference it
  487. def = malloc (sizeof(def_t));
  488. def->name = "COMPLEX TYPE";
  489. def->type = check;
  490. check->def = def;
  491. return check;
  492. }
  493. /*
  494. ============
  495. PR_SkipToSemicolon
  496. For error recovery, also pops out of nested braces
  497. ============
  498. */
  499. void PR_SkipToSemicolon (void)
  500. {
  501. do
  502. {
  503. if (!pr_bracelevel && PR_Check (";"))
  504. return;
  505. PR_Lex ();
  506. } while (pr_token[0]); // eof will return a null token
  507. }
  508. /*
  509. ============
  510. PR_ParseType
  511. Parses a variable type, including field and functions types
  512. ============
  513. */
  514. char pr_parm_names[MAX_PARMS][MAX_NAME];
  515. type_t *PR_ParseType (void)
  516. {
  517. type_t new;
  518. type_t *type;
  519. char *name;
  520. if (PR_Check ("."))
  521. {
  522. memset (&new, 0, sizeof(new));
  523. new.type = ev_field;
  524. new.aux_type = PR_ParseType ();
  525. return PR_FindType (&new);
  526. }
  527. if (!strcmp (pr_token, "float") )
  528. type = &type_float;
  529. else if (!strcmp (pr_token, "vector") )
  530. type = &type_vector;
  531. else if (!strcmp (pr_token, "float") )
  532. type = &type_float;
  533. else if (!strcmp (pr_token, "entity") )
  534. type = &type_entity;
  535. else if (!strcmp (pr_token, "string") )
  536. type = &type_string;
  537. else if (!strcmp (pr_token, "void") )
  538. type = &type_void;
  539. else
  540. {
  541. PR_ParseError ("\"%s\" is not a type", pr_token);
  542. type = &type_float; // shut up compiler warning
  543. }
  544. PR_Lex ();
  545. if (!PR_Check ("("))
  546. return type;
  547. // function type
  548. memset (&new, 0, sizeof(new));
  549. new.type = ev_function;
  550. new.aux_type = type; // return type
  551. new.num_parms = 0;
  552. if (!PR_Check (")"))
  553. {
  554. if (PR_Check ("..."))
  555. new.num_parms = -1; // variable args
  556. else
  557. do
  558. {
  559. type = PR_ParseType ();
  560. name = PR_ParseName ();
  561. strcpy (pr_parm_names[new.num_parms], name);
  562. new.parm_types[new.num_parms] = type;
  563. new.num_parms++;
  564. } while (PR_Check (","));
  565. PR_Expect (")");
  566. }
  567. return PR_FindType (&new);
  568. }