CE Source Preprocessor.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Edit{
  5. /******************************************************************************/
  6. Token* Source::TokenSource::previewNext()
  7. {
  8. if(tokens && InRange(token_index, *tokens))return &(*tokens)[token_index]; // first try custom token list
  9. if(source )return source->previewNextToken(*line_index, *line_token_index); // then try tokens from the source
  10. return null;
  11. }
  12. Token* Source::TokenSource::next(Bool only_cur_line)
  13. {
  14. if(tokens && InRange(token_index, *tokens))return &(*tokens)[token_index++]; // first try custom token list
  15. if(source )return source->getNextToken(*line_index, *line_token_index, only_cur_line); // then try tokens from the source
  16. return null;
  17. }
  18. void Source::TokenSource::removeLastRead() {if(tokens && token_index>0)tokens->remove(--token_index, true);}
  19. /******************************************************************************/
  20. Token* Source::previewNextToken(Int line_index, Int line_token_index)
  21. {
  22. if(InRange(line_index, lines))
  23. {
  24. Line &line=lines[line_index]; if(InRange(line_token_index, line.tokens))return &line.tokens[line_token_index];
  25. for(Int i=line_index+1; i<lines.elms(); i++)
  26. {
  27. Line &line=lines[i]; if(line.tokens.elms())return &line.tokens[0];
  28. }
  29. }
  30. return null;
  31. }
  32. Token* Source::getNextToken(Int &line_index, Int &line_token_index, Bool only_cur_line)
  33. {
  34. for(;;)
  35. {
  36. if(!InRange( line_index, lines ))return null; Line &line=lines[line_index];
  37. if( InRange(line_token_index, line.tokens))return &line.tokens[line_token_index++]; // if we still have tokens in current line
  38. if( only_cur_line )return null;
  39. line_token_index=0; line_index++; if(InRange(line_index, lines))lines[line_index].resetPreproc(true); // need to proceed to next line, when doing so we need to initialize its macro state
  40. }
  41. }
  42. /******************************************************************************/
  43. Int Source::findMacro(Memc<Macro> &macros, BStr &macro, Mems<Bool> *macro_used)
  44. {
  45. Int index; Bool found=macros.binarySearch(macro, index, CompareCS);
  46. if( found && macro_used && InRange(index, *macro_used) && (*macro_used)[index])found=false; // if macro was already used then skip
  47. return found ? index : ~index;
  48. }
  49. Int Source::findMacroToReplace(Memc<Macro> &macros, BStr &macro, TokenSource &ts, Mems<Bool> *macro_used)
  50. {
  51. Int index=findMacro(macros, macro, macro_used);
  52. if(InRange(index, macros) && macros[index].params>=0) // if macro was defined with (..) then require source tokens to have (..) as well, otherwise don't replace (this is how C++ works)
  53. {
  54. Token *next=ts.previewNext();
  55. if(!(next && *next=='('))return ~index; // if next token is not '(' then don't detect the macro replacement
  56. }
  57. return index;
  58. }
  59. Int Source::findMacroToReplace(Memc<Macro> &macros, BStr &macro, Int line_index, Int line_token_index)
  60. {
  61. Int index=findMacro(macros, macro);
  62. if(InRange(index, macros) && macros[index].params>=0) // if macro was defined with (..) then require source tokens to have (..) as well, otherwise don't replace (this is how C++ works)
  63. {
  64. Token *next=previewNextToken(line_index, line_token_index+1);
  65. if(!(next && *next=='('))return ~index; // if next token is not '(' then don't detect the macro replacement
  66. }
  67. return index;
  68. }
  69. /******************************************************************************/
  70. void Source::replaceMacro(Int macro_index, Memc<Macro> &macros, TokenSource &ts, Mems<Bool> &macro_used, Int depth, Int col, Line &line)
  71. {
  72. // read parameters of macro
  73. Memc<MacroParam> params;
  74. Macro &macro=macros[macro_index];
  75. if(macro.params>=0)
  76. {
  77. // store current position in token buffer
  78. Int prev_pos=ts.token_index;
  79. if(Token *token=ts.next())
  80. if(*token=='(')
  81. for(Int level=0; Token *token=ts.next(); )
  82. {
  83. switch((*token)[0])
  84. {
  85. case '(': level++; break;
  86. case ')': level--; break;
  87. }
  88. if( level<0)break; if(!params.elms())params.New();
  89. if(!level && *token==',')params.New ();
  90. else params.last().tokens.add(*token);
  91. }
  92. // remove read elements from token buffer
  93. REP(ts.token_index-prev_pos)ts.removeLastRead();
  94. // expand parameter macros
  95. /*Mems<Bool> macro_used; this shouldn't be done here, just rely on macro replacement coded below
  96. FREPA(params)
  97. {
  98. TokenSource ts;
  99. ts.tokens =&params[i].tokens;
  100. ts.token_index=0;
  101. for(; InRange(ts.token_index, *ts.tokens); )
  102. {
  103. Token &token=(*ts.tokens)[ts.token_index];
  104. Int macro_index=findMacro(macros, token);
  105. if( macro_index>=0)
  106. {
  107. ts.tokens->remove(ts.token_index, true); // remove macro token
  108. replaceMacro(macro_index, macros, ts, macro_used, 1, col, line);
  109. }else
  110. {
  111. ts.token_index++;
  112. }
  113. }
  114. }*/
  115. }
  116. // write
  117. Int token_index=ts.token_index;
  118. FREPA(macro.parts) // iterate through all parts of the macro
  119. {
  120. Int start=token_index;
  121. Macro::Part &part=macro.parts[i];
  122. if(InRange(part.param, params)) // if the part is an argument
  123. {
  124. MacroParam &mp=params[part.param];
  125. FREPA(mp.tokens)
  126. {
  127. Token &token=mp.tokens[i];
  128. ts.tokens->NewAt(token_index++).set(token, token.col, *token.line, token.type).macroPos(col, line).macroDepth(depth);
  129. }
  130. }else
  131. // TODO: can 'setCustom' be replaced with 'set' ? remember that Macro can be defined in one source, part.text BStr points to string data from that source, then other source uses this macro and its token BStr will point to string data from macro source
  132. if(part.text.is())ts.tokens->NewAt(token_index++).setCustom(part.text, col, line, part.type).macroPos(col, line).macroDepth(depth);
  133. for(; start<token_index; start++)if(Token *token=ts.tokens->addr(start)) // process all new tokens
  134. {
  135. if(*token=="__LINE__"){token->BStr::setCustom(S+line.line); token->type=TOKEN_NUMBER;} // replace '__LINE__' with code line
  136. }
  137. Int last =token_index-1,
  138. first=token_index-3;
  139. if(InRange(first, *ts.tokens)
  140. && InRange(last , *ts.tokens) && (*ts.tokens)[first+1]=="##") // if previous token was merger then merge the neighbours
  141. {
  142. Token &a=(*ts.tokens)[first],
  143. &b=(*ts.tokens)[last ];
  144. a.BStr::setCustom(a.asStr()+b.asStr());
  145. ts.tokens->remove(first+1, true).remove(first+1, true); token_index-=2;
  146. }
  147. }
  148. // verify result for other macros to be replaced (skipping those already processed)
  149. // macro.used=true; don't do here but only if another macro was detected below (this benefits in less often memory allocation requirement)
  150. for(; InRange(ts.token_index, *ts.tokens); )
  151. {
  152. Token &token=(*ts.tokens)[ts.token_index]; if(token.macro_depth<depth)break; // don't process parent tokens (process only from this or lower level)
  153. ts.next(); // increase token_index
  154. Int macro_index2=findMacroToReplace(macros, token, ts, &macro_used);
  155. if( macro_index2>=0 && macro_index2!=macro_index) // if we've detected another macro
  156. {
  157. if(!macro_used.elms())macro_used.setNumZero(macros.elms()); macro_used[macro_index]=true; // we must specify which macros were used
  158. ts.removeLastRead();
  159. replaceMacro(macro_index2, macros, ts, macro_used, depth+1, col, line);
  160. }
  161. }
  162. if(InRange(macro_index, macro_used))macro_used[macro_index]=false; // macro.used=false;
  163. }
  164. /******************************************************************************/
  165. Bool Source::getConditionalValue(Memc<Token> &tokens, Memc<Macro> &macros, Line &line)
  166. {
  167. Mems<Bool> macro_used;
  168. // replace "defined(x)" and "defined x" to "1" or "0"
  169. FREPA(tokens)if(tokens[i]=="defined")
  170. {
  171. tokens.remove(i, true); // remove 'defined'
  172. if(InRange(i, tokens) && tokens[i]=='(')tokens.remove(i, true).remove(i+1, true); // remove '(' ')' in "defined(x)"
  173. if(InRange(i, tokens))
  174. {
  175. Token &macro=tokens[i];
  176. macro.type=TOKEN_NUMBER;
  177. macro.BStr::setBorrowed((findMacro(macros, macro)>=0) ? u"1" : u"0"); // if macro exists, then set "1", if not then set "0"
  178. }
  179. }
  180. // replace macros
  181. FREPA(tokens)
  182. {
  183. Token &token=tokens[i];
  184. if(token.type==TOKEN_CODE || token.type==TOKEN_KEYWORD)
  185. {
  186. Int macro_index =findMacroToReplace(macros, token, line.line, i);
  187. if( macro_index>=0)
  188. {
  189. tokens.remove(i, true); // remove macro
  190. TokenSource ts;
  191. ts.tokens =&tokens;
  192. ts.token_index=i;
  193. // replace macro
  194. REPAO(macro_used)=false; replaceMacro(macro_index, macros, ts, macro_used, 1, 0, line);
  195. // process all remaining tokens
  196. for(; Token *token=ts.next(); )
  197. {
  198. macro_index =findMacroToReplace(macros, *token, ts);
  199. if(macro_index>=0)
  200. {
  201. ts.removeLastRead();
  202. REPAO(macro_used)=false; replaceMacro(macro_index, macros, ts, macro_used, 1, 0, line);
  203. }
  204. }
  205. break;
  206. }
  207. }
  208. }
  209. Str s; FREPA(tokens)
  210. {
  211. Token &token=tokens[i];
  212. s.space()+=((token.type==TOKEN_CODE || token.type==TOKEN_KEYWORD) ? "0" : token.asStr()); // replace all text with "0" value
  213. }
  214. return CalculateI(s)!=0;
  215. }
  216. /******************************************************************************/
  217. void Source::preprocess(Memc<Macro> &macros, Int &line_index, Memc<Token*> &temp, Bool allow_defines, Memc<PrepCond> &prep_if)
  218. {
  219. Bool vis =(recursive<=1 && parse_count==0); // if apply visuals
  220. Int start_line_index =line_index;
  221. Line &line =lines[line_index]; line.resetPreproc(false); if(vis)line.tokens_preproc_condition_unavailable=false;
  222. Memc<Token> &tokens=line.tokens;
  223. // preprocessor tokens - detect macro changes
  224. if(line.preproc)
  225. {
  226. if(!line.starts_with_preproc && !line.starts_with_macro_param)
  227. {
  228. Bool handled_unavailable=true;
  229. if(tokens.elms()>=2 && tokens[0]=='#')
  230. {
  231. if(tokens[1]=="define" && allow_defines) // add new macro
  232. {
  233. if(!prep_if.elms() || prep_if.last().currently_valid)
  234. {
  235. if(Token *name=tokens.addr(2))
  236. if(name->type==TOKEN_CODE || name->type==TOKEN_KEYWORD)
  237. {
  238. // line.macros=macros; line.has_macros=true;
  239. Int index=findMacro(macros, *name);
  240. Macro &macro=((index>=0) ? macros[index].reset() : macros.NewAt(~index).set(*name)); macro.def=line;
  241. Int i=3; temp.clear();
  242. if(InRange(i, tokens) && tokens[i]=='(' && tokens[i]()==(*name)()+name->length()) // if macro name followed directly by '('
  243. {
  244. // detect macro params
  245. macro.params=0;
  246. for(i++; i<tokens.elms(); ) // skip '('
  247. {
  248. Token &token=tokens[i++];
  249. if(token==',')continue;
  250. if(token.type==TOKEN_CODE)
  251. {
  252. macro.params++;
  253. temp.add(&token);
  254. continue;
  255. }
  256. break;
  257. }
  258. }
  259. // get macro body
  260. for(; Token *token=getNextToken(line_index, i, true); )
  261. {
  262. if(*token=='\\' && token->macro_col<0 && token->col==token->line->length()-1) // if this is \ character located at the end of the line
  263. {
  264. if(!InRange(line_index+1, lines))break; // if there is no next line then break
  265. i=0; // start with first token in next line
  266. Line &line=lines[++line_index]; line.resetPreproc(false); if(vis)line.tokens_preproc_condition_unavailable=false; // increase line counter and initialize the next line
  267. }else
  268. {
  269. if(token->type==TOKEN_CODE)REPA(temp)if((*temp[i])==*token)
  270. {
  271. macro.parts.New().set(token->type, i, null);
  272. goto added;
  273. }
  274. macro.parts.New().set(token->type, -1, token);
  275. added:;
  276. }
  277. }
  278. }
  279. }else if(vis)line.tokens_preproc_condition_unavailable=true;
  280. }else
  281. if(tokens[1]=="undef" && allow_defines) // remove macro
  282. {
  283. if(!prep_if.elms() || prep_if.last().currently_valid)
  284. {
  285. // TODO: line.ends_with_preproc
  286. if(Token *name=tokens.addr(2))
  287. if(name->type==TOKEN_CODE || name->type==TOKEN_KEYWORD)
  288. {
  289. Int index=findMacro(macros, *name); // if(index>=0){line.has_macros=true; FREPA(macros)if(i!=index)line.macros.add(macros[i]);}
  290. macros.remove(index, true);
  291. }
  292. }else if(vis)line.tokens_preproc_condition_unavailable=true;
  293. }else
  294. if(tokens[1]=="if")
  295. {
  296. // TODO: line.ends_with_preproc
  297. if(!prep_if.elms() || prep_if.last().currently_valid)
  298. {
  299. for(Int i=2; i<tokens.elms(); i++)line.tokens_preproc.New()=tokens[i];
  300. Bool value=getConditionalValue(line.tokens_preproc, macros, line);
  301. prep_if.New().set(!value, value);
  302. }else
  303. {
  304. prep_if.New().set(false, false);
  305. if(vis)line.tokens_preproc_condition_unavailable=true;
  306. }
  307. }else
  308. if(tokens[1]=="ifdef")
  309. {
  310. if(!prep_if.elms() || prep_if.last().currently_valid)
  311. {
  312. line.tokens_preproc.New().setBorrowed(u"defined", -1, 0, line, TOKEN_PREPROC);
  313. for(Int i=2; i<tokens.elms(); i++)line.tokens_preproc.New()=tokens[i];
  314. Bool value=getConditionalValue(line.tokens_preproc, macros, line);
  315. prep_if.New().set(!value, value);
  316. }else
  317. {
  318. prep_if.New().set(false, false);
  319. if(vis)line.tokens_preproc_condition_unavailable=true;
  320. }
  321. }else
  322. if(tokens[1]=="ifndef")
  323. {
  324. if(!prep_if.elms() || prep_if.last().currently_valid)
  325. {
  326. line.tokens_preproc.New().setBorrowed(u"!" , -1, 0, line, TOKEN_OPERATOR);
  327. line.tokens_preproc.New().setBorrowed(u"defined", -1, 0, line, TOKEN_PREPROC );
  328. for(Int i=2; i<tokens.elms(); i++)line.tokens_preproc.New()=tokens[i];
  329. Bool value=getConditionalValue(line.tokens_preproc, macros, line);
  330. prep_if.New().set(!value, value);
  331. }else
  332. {
  333. prep_if.New().set(false, false);
  334. if(vis)line.tokens_preproc_condition_unavailable=true;
  335. }
  336. }else
  337. if(tokens[1]=="elif")
  338. {
  339. // TODO: line.ends_with_preproc
  340. if(prep_if.elms() && prep_if.last().can_enter)
  341. {
  342. for(Int i=2; i<tokens.elms(); i++)line.tokens_preproc.New()=tokens[i];
  343. Bool value=getConditionalValue(line.tokens_preproc, macros, line);
  344. prep_if.last().set(!value, value);
  345. }else
  346. {
  347. if(!prep_if.elms())prep_if.New();
  348. prep_if.last().set(false, false);
  349. }
  350. if(vis && prep_if.elms()>=2 && !prep_if[prep_if.elms()-2].currently_valid)line.tokens_preproc_condition_unavailable=true;
  351. }else
  352. if(tokens[1]=="else")
  353. {
  354. if(prep_if.elms())
  355. {
  356. Bool value=prep_if.last().can_enter;
  357. prep_if.last().set(false, value);
  358. }
  359. if(vis && prep_if.elms()>=2 && !prep_if[prep_if.elms()-2].currently_valid)line.tokens_preproc_condition_unavailable=true;
  360. }else
  361. if(tokens[1]=="endif")
  362. {
  363. prep_if.removeLast();
  364. if(vis && prep_if.elms() && !prep_if.last().currently_valid)line.tokens_preproc_condition_unavailable=true;
  365. }else
  366. handled_unavailable=false;
  367. }else
  368. handled_unavailable=false;
  369. if(!handled_unavailable)
  370. if(vis && prep_if.elms() && !prep_if.last().currently_valid)line.tokens_preproc_condition_unavailable=true;
  371. }
  372. // if this is a preprocess line, then no actual tokens should be used for the code compilation
  373. for(Int i=start_line_index; i<=line_index; i++) // call for each processed line
  374. {
  375. Line &line=lines[i];
  376. line.tokens_preproc_use=true;
  377. line.tokens_preproc.clear();
  378. }
  379. }else
  380. if(prep_if.elms() && !prep_if.last().currently_valid)
  381. {
  382. // if there was a preprocess condition which wasn't met, then no actual tokens should be used for the code compilation
  383. if(vis)line.tokens_preproc_condition_unavailable=true;
  384. line.tokens_preproc_use=true;
  385. line.tokens_preproc.clear();
  386. }else
  387. if(macros.elms()) // normal line, try to replace tokens with macros
  388. {
  389. Mems<Bool> macro_used;
  390. FREPA(tokens)
  391. {
  392. Token &token=tokens[i];
  393. if(token.type==TOKEN_CODE || token.type==TOKEN_KEYWORD)
  394. {
  395. Int macro_index =findMacroToReplace(macros, token, line_index, i);
  396. if( macro_index>=0) // we've encountered token which should be overriden by macro
  397. {
  398. // replace with macro
  399. line .tokens_preproc_use=true;
  400. token.macro =true;
  401. for(Int j=0; j<i; j++)line.tokens_preproc.add(tokens[j]); // copy all tokens up to now into preprocessed token buffer
  402. i++; // skip macro token
  403. TokenSource ts;
  404. ts.tokens =&line.tokens_preproc;
  405. ts.token_index = line.tokens_preproc.elms();
  406. ts.source =this;
  407. ts.line_index =&line_index;
  408. ts.line_token_index=&i;
  409. // replace macro
  410. REPAO(macro_used)=false; replaceMacro(macro_index, macros, ts, macro_used, 1, token.col, *token.line);
  411. // process all remaining in this line
  412. ts.token_index=ts.tokens->elms(); // move at the end so next token will be from source
  413. for(; Token *token=ts.next(true); )
  414. {
  415. Int macro_index=findMacroToReplace(macros, *token, ts);
  416. if( macro_index>=0){token->macro=true; REPAO(macro_used)=false; replaceMacro(macro_index, macros, ts, macro_used, 1, token->col, *token->line);} // if it's a macro, then trigger macro replacement function
  417. else {ts.tokens->add(*token); } // copy normally
  418. ts.token_index=ts.tokens->elms(); // move at the end so next token will be from source
  419. }
  420. break;
  421. }
  422. }
  423. }
  424. }
  425. //return line.has_macros ? line.macros : macros;
  426. }
  427. /******************************************************************************/
  428. void Source::detectDefines()
  429. {
  430. // TODO:
  431. if(active)
  432. {
  433. }
  434. }
  435. /******************************************************************************/
  436. void Source::preprocess(Int from, Int num)
  437. {
  438. tokens.clear();
  439. if(active)
  440. {
  441. // preprocess
  442. Int max=lines.elms()-1,
  443. to =((num<0) ? max : Min(from+num-1, max));
  444. MAX(from, 0);
  445. if(preproc_line_changed>=0) // if any of the preprocessor lines was changed, then update from that line till the end of the file
  446. {
  447. MIN(from, preproc_line_changed); preproc_line_changed=-1;
  448. from=0; // preprocess from the start, because currently 'prep_if' is created from current position only
  449. to=max;
  450. }
  451. if(from<=to)
  452. {
  453. // preprocess tokens
  454. if ( from>0 && (lines[from-1].starts_with_macro_param || lines[from-1].starts_with_preproc || lines[from-1].tokens_preproc_condition_unavailable)) from--;
  455. for(; from>0 && (lines[from ].starts_with_macro_param || lines[from ].starts_with_preproc || lines[from ].tokens_preproc_condition_unavailable); from--); // go to first line which doesn't start with macro param or preprocess
  456. for(; InRange(to+1, lines) && (lines[ to+1].starts_with_macro_param || lines[ to+1].starts_with_preproc ); to++); // expand range to cover all lines which start with macro param or preprocess
  457. //Memc<Macro > *macros=&macrosForLine(from);
  458. Memc<Token* > temp;
  459. Memc<PrepCond> prep_if;
  460. Int cur=from; for(; cur<=to; cur++)preprocess(ProjectMacros, cur, temp, false, prep_if); // preprocess lines
  461. FREPA(view_lines){ViewLine &line=view_lines[i]; if(line.line()>=from && line.line()<cur)line.text_valid=false;} // force text reset on all processed lines (use 'cur' because it may be bigger than 'to')
  462. }
  463. }
  464. setTokenPtrs();
  465. }
  466. /******************************************************************************/
  467. }}
  468. /******************************************************************************/