QSPGameCode.cs 98 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Text;
  6. using System.Threading;
  7. using System.ComponentModel;
  8. namespace Analyser
  9. {
  10. public class Location : Common
  11. {
  12. QSPGameCode m_gamecode;
  13. string m_name;
  14. int m_line;
  15. bool m_start; //Стартовая локация
  16. List<string> location_codeline_text;
  17. Dictionary<int, int> location_codeline_level;
  18. int currentLine;
  19. bool currentRoot;
  20. enum ControlBlockType
  21. {
  22. None,
  23. SL_If,
  24. SL_Else,
  25. SL_Act,
  26. ML_If,
  27. ML_Else,
  28. ML_Act,
  29. IfCondition,
  30. ElseIfCondition,
  31. ActCondition
  32. }
  33. struct ControlLine
  34. {
  35. public ControlBlockType controlBlock;
  36. public int line;
  37. }
  38. public Location(QSPGameCode code, string name, int line, bool start)
  39. {
  40. m_gamecode = code;
  41. m_name = name;
  42. m_line = line;
  43. m_start = start;
  44. location_codeline_text = null;
  45. location_codeline_level = null;
  46. }
  47. public string GetName()
  48. {
  49. return m_name;
  50. }
  51. public int GetLine()
  52. {
  53. return m_line;
  54. }
  55. public int GetCodeLinesCount()
  56. {
  57. return location_codeline_text.Count;
  58. }
  59. public void GetCodeLine(int lineNum, ref string text, ref int level)
  60. {
  61. //Нужно для утилиты форматирования
  62. int realNum = lineNum + 1;
  63. text = location_codeline_text[lineNum];
  64. if (location_codeline_level.ContainsKey(realNum))
  65. level = location_codeline_level[realNum];
  66. else
  67. level = INVALID_INDEX;
  68. return;
  69. }
  70. new void SubmitError(string text, int line)
  71. {
  72. if (currentRoot)
  73. Common.SubmitError(text, line);
  74. else
  75. Common.SubmitError(text, currentLine);
  76. }
  77. new void SubmitWarning(string text, int line)
  78. {
  79. if (currentRoot)
  80. Common.SubmitWarning(text, line);
  81. else
  82. Common.SubmitWarning(text, currentLine);
  83. }
  84. bool qspCompileExprPushOpCode(ref int[] opStack, ref int opSp, ref int[] argStack, ref int argSp, int opCode)
  85. {
  86. if ((opSp == QSP_STACKSIZE - 1) || (argSp == QSP_STACKSIZE - 1))
  87. {
  88. SubmitError("Quite complicated expression", currentLine);
  89. return false;
  90. }
  91. opStack[++opSp] = opCode;
  92. argStack[++argSp] = (opCode < (int)QspFunctionType.First_Function) ? qspOps[opCode].MinArgsCount : 0;
  93. return true;
  94. }
  95. bool qspAppendToCompiled(ref int itemsCount)
  96. {
  97. if (itemsCount == QSP_MAXITEMS)
  98. {
  99. SubmitError("Quite many arguments in the expression", currentLine);
  100. return false;
  101. }
  102. ++itemsCount;
  103. return true;
  104. }
  105. public bool ParseLocation(List<string> code, bool root)
  106. {
  107. int quote = (int)QuoteType.None;
  108. if (root)
  109. {
  110. currentRoot = true;
  111. currentLine = 0;
  112. location_codeline_text = new List<string>(code);
  113. location_codeline_level = new Dictionary<int, int>();
  114. }
  115. //Склеиваем строки
  116. List<int> lineIndexes = new List<int>();
  117. List<string> escapedLines = new List<string>();
  118. int linesCount = code.Count;
  119. int oldLine = 0;
  120. int curLine = 0;
  121. int curlyLevel = 0;
  122. string extraLine = "";
  123. while (curLine < linesCount)
  124. {
  125. string line = code.ToArray()[curLine].Trim(WhiteSpace);
  126. int pos = 0;
  127. while (pos < line.Length)
  128. {
  129. char c = line[pos];
  130. if (c == '\'')
  131. {
  132. //Апостроф
  133. if (quote == (int)QuoteType.None)
  134. {
  135. quote = (int)QuoteType.Single;
  136. }
  137. else if (quote == (int)QuoteType.Single)
  138. {
  139. if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
  140. {
  141. //Экранированный апостроф
  142. pos++;
  143. }
  144. else
  145. {
  146. quote = (int)QuoteType.None;
  147. }
  148. }
  149. }
  150. else if (c == '"')
  151. {
  152. //Кавычка
  153. if (quote == (int)QuoteType.None)
  154. {
  155. quote = (int)QuoteType.Double;
  156. }
  157. else if (quote == (int)QuoteType.Double)
  158. {
  159. if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
  160. {
  161. //Экранированная кавычка
  162. pos++;
  163. }
  164. else
  165. {
  166. quote = (int)QuoteType.None;
  167. }
  168. }
  169. }
  170. else if (quote == (int)QuoteType.None)
  171. {
  172. if (c == '{')
  173. {
  174. curlyLevel++;
  175. }
  176. else if (c == '}')
  177. {
  178. if (curlyLevel == 0)
  179. {
  180. SubmitError("Closing curly brace without opening one", oldLine + 1);
  181. return false;
  182. }
  183. curlyLevel--;
  184. }
  185. }
  186. pos++;
  187. }
  188. if ((curlyLevel > 0) || (quote != (int)QuoteType.None) || line.EndsWith(" _"))
  189. {
  190. if (line.EndsWith(" _"))
  191. line = line.Substring(0, line.Length - 2);
  192. extraLine += line;
  193. if (curlyLevel > 0)
  194. extraLine += "\n";//Вставляем разделитель для строк, потом по нему "разобьем" строки
  195. if (curLine == linesCount - 1)
  196. {
  197. lineIndexes.Add(oldLine + 1);
  198. string escaped = extraLine + line;
  199. escapedLines.Add(escaped.Trim(WhiteSpace));
  200. }
  201. }
  202. else
  203. {
  204. lineIndexes.Add(oldLine + 1);
  205. string escaped = extraLine + line;
  206. escapedLines.Add(escaped.Trim(WhiteSpace));
  207. oldLine = curLine + 1;
  208. extraLine = "";
  209. }
  210. curLine++;
  211. }
  212. //Проверка на незакрытые в конце локации многострочные строки
  213. if (quote != (int)QuoteType.None)
  214. {
  215. SubmitError("Unclosed string", oldLine + 1);
  216. return false;
  217. }
  218. //Проверка на незакрытые в конце локации фигурные скобки
  219. if (curlyLevel > 0)
  220. {
  221. SubmitError("Unclosed curly bracket", oldLine + 1);
  222. return false;
  223. }
  224. //TODO
  225. // FOR
  226. // перечисления asd|12|ddd
  227. //Разбираем код
  228. int lineNum = 0;
  229. int linePlainNum = 0;
  230. string block = "";
  231. string quotedText = "";
  232. int controlBlock = (int)ControlBlockType.None;
  233. Stack<ControlLine> ControlStack = new Stack<ControlLine>();
  234. List<string> blockGroup = new List<string>();
  235. List<bool> blockInGroupIsText = new List<bool>();
  236. int groupInnerCounter = 0;
  237. bool blockStarted = false;
  238. bool blockCompleted = false;
  239. bool blockGroupStarted = false;
  240. bool blockGroupCompleted = false;
  241. bool quotedTextCompleted = false;
  242. string rawText = "";
  243. string debugText = "";
  244. foreach (string line in escapedLines)
  245. {
  246. lineNum = lineIndexes[linePlainNum];
  247. linePlainNum++;
  248. int startIndentLevel = 0;
  249. int endIndentLevel = 0;
  250. if (currentRoot)
  251. {
  252. currentLine = lineNum;
  253. //Вычисляем уровень вложенности(для утилиты форматирования кода)
  254. int stackSize = ControlStack.Count;
  255. if (stackSize > 0)
  256. startIndentLevel = stackSize;
  257. }
  258. int pos = 0;
  259. int firstSymbolPos = INVALID_INDEX;
  260. int blockStartPos = INVALID_INDEX;
  261. int lastIfPos = INVALID_INDEX;
  262. int lastActPos = INVALID_INDEX;
  263. int bracketLevel = 0;
  264. bool comment = false;
  265. bool label = false;
  266. string labelText = "";
  267. bool singleBlockGroup = false;
  268. //Разбор строки
  269. while (pos < line.Length)
  270. {
  271. bool appendDelimiter = false;
  272. String delimiterToAppend = "";
  273. char c = line[pos];
  274. if ((c.ToString().IndexOfAny(WhiteSpace) != 0) && (firstSymbolPos == INVALID_INDEX))
  275. {
  276. firstSymbolPos = pos;
  277. }
  278. if (c == '\'')
  279. {
  280. //Апостроф
  281. if (quote == (int)QuoteType.None)
  282. {
  283. quote = (int)QuoteType.Single;
  284. quotedText = "";
  285. if (blockStarted && !comment)
  286. blockCompleted = true;
  287. //для отладки
  288. if (rawText.Length == 0)
  289. rawText += c;
  290. else
  291. rawText += Environment.NewLine + c;
  292. }
  293. else if (quote == (int)QuoteType.Single)
  294. {
  295. if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
  296. {
  297. //Экранированный апостроф
  298. pos++;
  299. quotedText += c;
  300. }
  301. else
  302. {
  303. quote = (int)QuoteType.None;
  304. if (!comment && !label)
  305. quotedTextCompleted = true;
  306. }
  307. //для отладки
  308. rawText += c;
  309. }
  310. else
  311. {
  312. quotedText += c;
  313. //для отладки
  314. rawText += c;
  315. }
  316. }
  317. else if (c == '"')
  318. {
  319. //Кавычка
  320. if (quote == (int)QuoteType.None)
  321. {
  322. quote = (int)QuoteType.Double;
  323. quotedText = "";
  324. if (blockStarted && !comment)
  325. blockCompleted = true;
  326. //для отладки
  327. if (rawText.Length == 0)
  328. rawText += c;
  329. else
  330. rawText += Environment.NewLine + c;
  331. }
  332. else if (quote == (int)QuoteType.Double)
  333. {
  334. if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
  335. {
  336. //Экранированная кавычка
  337. pos++;
  338. quotedText += c;
  339. }
  340. else
  341. {
  342. quote = (int)QuoteType.None;
  343. if (!comment && !label)
  344. quotedTextCompleted = true;
  345. }
  346. //для отладки
  347. rawText += c;
  348. }
  349. else
  350. {
  351. quotedText += c;
  352. //для отладки
  353. rawText += c;
  354. }
  355. }
  356. else if (comment)
  357. {
  358. //Здесь игнорируем все до самого конца строки, но учитываем переводы строк внутри кавычек и апострофов.
  359. }
  360. else if (quote != (int)QuoteType.None)
  361. {
  362. //Строка текста внутри кавычек или апострофов
  363. quotedText += c;
  364. //для отладки
  365. rawText += c;
  366. }
  367. else if (c == '{')
  368. {
  369. if (blockStarted && !comment)
  370. blockCompleted = true;
  371. //Записываем содержимое фигурных скобок
  372. string curlyText = "";
  373. curlyLevel = 1;
  374. pos++;
  375. int curlyQuote = (int)QuoteType.None;
  376. while (pos < line.Length)
  377. {
  378. char c2 = line[pos];
  379. if (c2 == '\'')
  380. {
  381. //Апостроф
  382. if (curlyQuote == (int)QuoteType.None)
  383. {
  384. curlyQuote = (int)QuoteType.Single;
  385. }
  386. else if (curlyQuote == (int)QuoteType.Single)
  387. {
  388. if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
  389. {
  390. //Экранированный апостроф
  391. curlyText += c2;
  392. pos++;
  393. c2 = line[pos];
  394. }
  395. else
  396. {
  397. curlyQuote = (int)QuoteType.None;
  398. }
  399. }
  400. }
  401. else if (c2 == '"')
  402. {
  403. //Кавычка
  404. if (curlyQuote == (int)QuoteType.None)
  405. {
  406. curlyQuote = (int)QuoteType.Double;
  407. }
  408. else if (curlyQuote == (int)QuoteType.Double)
  409. {
  410. if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
  411. {
  412. //Экранированная кавычка
  413. curlyText += c2;
  414. pos++;
  415. c2 = line[pos];
  416. }
  417. else
  418. {
  419. curlyQuote = (int)QuoteType.None;
  420. }
  421. }
  422. }
  423. else if (curlyQuote == (int)QuoteType.None)
  424. {
  425. if (c2 == '{')
  426. {
  427. curlyLevel++;
  428. }
  429. else if (c2 == '}')
  430. {
  431. curlyLevel--;
  432. if (curlyLevel == 0)
  433. break;
  434. }
  435. }
  436. curlyText += c2;
  437. pos++;
  438. }
  439. if (curlyLevel > 0)
  440. {
  441. SubmitError("Internal error of the analyzer - unclosed curly bracket \"{\"", currentLine);
  442. break;
  443. }
  444. if (curlyParsing)
  445. {
  446. //Парсим содержимое фигурных скобок
  447. List<string> curlyLines = new List<string>(curlyText.Split('\n'));
  448. currentRoot = false;
  449. ParseLocation(curlyLines, currentRoot);
  450. currentRoot = root;
  451. //Добавляем пустую "строку в кавычках", чтобы анализатор не ругался на отсутствие параметра
  452. quotedText = "";
  453. }
  454. else
  455. {
  456. quotedText = curlyText;
  457. }
  458. quotedTextCompleted = true;
  459. }
  460. else
  461. {
  462. //Обычные символы
  463. if (label)
  464. {
  465. if (c == '&')
  466. {
  467. if (labelText.Trim(WhiteSpace).Equals(":"))
  468. {
  469. SubmitError("Empty label", lineNum);
  470. return false;
  471. }
  472. if (quote != (int)QuoteType.None)
  473. {
  474. SubmitError("Unclosed string in the label name", lineNum);
  475. return false;
  476. }
  477. label = false;
  478. }
  479. else
  480. {
  481. labelText += c;
  482. }
  483. }
  484. else if ((c == ':') && ((controlBlock == (int)ControlBlockType.IfCondition) ||
  485. (controlBlock == (int)ControlBlockType.ElseIfCondition)))
  486. {
  487. //Разбор условия
  488. if (blockStarted)
  489. blockCompleted = true;
  490. blockGroupCompleted = true;
  491. //Двоеточие после условия
  492. if ((pos == line.Length - 1))
  493. {
  494. //В конце строки - многострочный IF или ELSEIF
  495. if (firstSymbolPos == lastIfPos)
  496. {
  497. if (controlBlock == (int)ControlBlockType.IfCondition)
  498. {
  499. ControlLine cline;
  500. cline.line = lineNum;
  501. cline.controlBlock = ControlBlockType.ML_If;
  502. ControlStack.Push(cline);
  503. }
  504. else
  505. {
  506. ControlLine cline = ControlStack.Pop();
  507. if (cline.controlBlock != ControlBlockType.ML_If)
  508. {
  509. SubmitError("ELSEIF without IF", lineNum);
  510. return false;
  511. }
  512. cline.line = lineNum;
  513. ControlStack.Push(cline);
  514. }
  515. controlBlock = (int)ControlBlockType.ML_If;
  516. }
  517. else
  518. {
  519. if (controlBlock == (int)ControlBlockType.IfCondition)
  520. SubmitError("Multiline IF should be placed at the beginning of the line", lineNum);
  521. else
  522. SubmitError("Multiline ELSEIF should be placed at the beginning of the line", lineNum);
  523. return false;
  524. }
  525. }
  526. else if (controlBlock == (int)ControlBlockType.IfCondition)
  527. {
  528. //Строка не заканчивается - однострочный IF
  529. if (controlBlock == (int)ControlBlockType.IfCondition)
  530. {
  531. ControlLine cline;
  532. cline.line = lineNum;
  533. cline.controlBlock = ControlBlockType.SL_If;
  534. ControlStack.Push(cline);
  535. controlBlock = (int)cline.controlBlock;
  536. groupInnerCounter = 0;
  537. }
  538. else
  539. {
  540. SubmitError("ELSEIF cannot be used in single line IF", lineNum);
  541. return false;
  542. }
  543. }
  544. else
  545. {
  546. SubmitError("An operator cannot be placed after colon\":\" in multiline ELSEIF", lineNum);
  547. return false;
  548. }
  549. }
  550. else if ((c == ':') && (controlBlock == (int)ControlBlockType.ActCondition))
  551. {
  552. //Разбор аргумента
  553. if (blockStarted)
  554. blockCompleted = true;
  555. blockGroupCompleted = true;
  556. //Двоеточие после ACT
  557. if (pos == line.Length - 1)
  558. {
  559. //В конце строки - многострочный ACT
  560. if (firstSymbolPos == lastActPos)
  561. {
  562. controlBlock = (int)ControlBlockType.ML_Act;
  563. ControlLine cline;
  564. cline.line = lineNum;
  565. cline.controlBlock = ControlBlockType.ML_Act;
  566. ControlStack.Push(cline);
  567. }
  568. else
  569. {
  570. SubmitError("Multiline ACT should be placed at the beginning of the line", lineNum);
  571. return false;
  572. }
  573. }
  574. else
  575. {
  576. //Строка не заканчивается - однострочный ACT
  577. controlBlock = (int)ControlBlockType.SL_Act;
  578. groupInnerCounter = 0;
  579. }
  580. }
  581. else if (!comment && (c == '!') && !blockGroupStarted && !blockStarted)
  582. {
  583. //Начало комментария
  584. comment = true;
  585. }
  586. else if ((c == ':') && (firstSymbolPos == pos))
  587. {
  588. //Начало метки
  589. label = true;
  590. }
  591. else if (c.ToString().IndexOfAny(Delimiters) == 0)
  592. {
  593. if ((c == '&') && (bracketLevel == 0))
  594. {
  595. if (controlBlock == (int)ControlBlockType.IfCondition)
  596. {
  597. //В условии IF недопустимо использование "&" вне скобок
  598. SubmitError("Redundant \"&\": perhaps should be \"AND\"", lineNum);
  599. return false;
  600. }
  601. else if (controlBlock == (int)ControlBlockType.ActCondition)
  602. {
  603. //В названии ACT недопустимо использование "&" вне скобок
  604. SubmitError("Redundant \"&\"", lineNum);
  605. return false;
  606. }
  607. else
  608. {
  609. if (blockStarted)
  610. blockCompleted = true;
  611. if (blockGroupStarted)
  612. blockGroupCompleted = true;
  613. if (blockStarted && !blockGroupStarted)
  614. singleBlockGroup = true;
  615. }
  616. }
  617. else if (blockStarted && (c == ' ') && StartOfMultiWordOperator(block))
  618. {
  619. //Составной оператор - DEL ACT, DEL OBJ
  620. block += c;
  621. }
  622. else if (blockStarted && (c == ' ') && (qspGetStatCode(block) == (int)QspStatementType.Close) &&
  623. (line.Length > pos + 3) && line.Substring(pos + 1, 3).Equals("ALL", StringComparison.OrdinalIgnoreCase))
  624. {
  625. //CLOSE ALL
  626. block += c;
  627. }
  628. else if (!blockStarted && (c == '*'))
  629. {
  630. //Возможно, *PL, *P, *NL
  631. blockStarted = true;
  632. blockCompleted = false;
  633. block += c;
  634. blockStartPos = pos;
  635. }
  636. else if (!blockStarted && (c == '['))
  637. {
  638. //Квадратная скобка должна идти вплотную к имени массива
  639. SubmitError("A square bracket has to be placed just behind the name of the array, with no spaces", lineNum);
  640. return false;
  641. }
  642. else
  643. {
  644. //Самостоятельные знаки
  645. if (c == '(')
  646. {
  647. bracketLevel++;
  648. }
  649. else if (c == ')')
  650. {
  651. if (bracketLevel == 0)
  652. {
  653. SubmitError("Redundant bracket \")\"", lineNum);
  654. return false;
  655. }
  656. bracketLevel--;
  657. }
  658. bool whiteSpace = c.ToString().IndexOfAny(WhiteSpace) == 0;
  659. //Особый учет для последовательностей >=, => и т.д.
  660. bool comparer = pos + 1 < line.Length;
  661. String cmp = "";
  662. if (comparer)
  663. {
  664. cmp = line.Substring(pos, 2);
  665. comparer = cmp.Equals("<=") || cmp.Equals(">=") || cmp.Equals("=>") || cmp.Equals("=<") || cmp.Equals("<>") ||
  666. cmp.Equals("+=") || cmp.Equals("-=");
  667. }
  668. if (comparer)
  669. {
  670. //<= >= => =< <> += -=
  671. if (blockStarted)
  672. {
  673. appendDelimiter = true;
  674. delimiterToAppend = cmp;
  675. }
  676. else
  677. {
  678. blockStarted = true;
  679. blockStartPos = pos;
  680. block = cmp;
  681. }
  682. blockCompleted = true;
  683. pos++;
  684. }
  685. else if (blockStarted)
  686. {
  687. blockCompleted = true;
  688. if (!whiteSpace)
  689. {
  690. appendDelimiter = true;
  691. delimiterToAppend += c;
  692. }
  693. else
  694. {
  695. //Обрабатываем END IF, END ACT
  696. int blockCode = qspGetStatCode(block);
  697. if (blockCode == (int)QspStatementType.End)
  698. {
  699. int nextPos = line.LastIndexOfAny(WhiteSpace, blockStartPos + block.Length) + 1;
  700. if (nextPos < line.Length)
  701. {
  702. int delimPos = line.IndexOfAny(Delimiters, nextPos);
  703. string nextWord = "";
  704. if (delimPos == INVALID_INDEX)
  705. nextWord = line.Substring(nextPos);
  706. else
  707. nextWord = line.Substring(nextPos, delimPos - nextPos);
  708. int nextCode = qspGetStatCode(nextWord);
  709. if ((nextCode == (int)QspStatementType.If) || (nextCode == (int)QspStatementType.Act))
  710. {
  711. pos = nextPos + nextWord.Length - 1;
  712. }
  713. }
  714. }
  715. }
  716. }
  717. else if (!whiteSpace)
  718. {
  719. blockStarted = true;
  720. blockCompleted = true;
  721. blockStartPos = pos;
  722. block += c;
  723. }
  724. }
  725. }
  726. else
  727. {
  728. //Просто буквы
  729. if (!blockStarted)
  730. {
  731. blockStarted = true;
  732. blockCompleted = false;
  733. blockStartPos = pos;
  734. }
  735. block += c;
  736. }
  737. }
  738. //Последний символ в строке
  739. if (blockStarted && (pos == line.Length - 1))
  740. {
  741. blockCompleted = true;
  742. }
  743. if (blockCompleted || quotedTextCompleted)
  744. {
  745. if (!quotedTextCompleted && (block.Length == 0))
  746. {
  747. SubmitError("Internal error of analyzer! Empty block!", lineNum);
  748. return false;
  749. }
  750. debugText += "[" + block + "] ";
  751. bool skip = false;
  752. int blockCode = qspGetStatCode(block);
  753. if (blockCode == (int)QspStatementType.If)
  754. {
  755. controlBlock = (int)ControlBlockType.IfCondition;
  756. debugText += "<IfCondition> ";
  757. lastIfPos = blockStartPos;
  758. }
  759. if (blockCode == (int)QspStatementType.Act)
  760. {
  761. controlBlock = (int)ControlBlockType.ActCondition;
  762. debugText += "<ActCondition> ";
  763. lastActPos = blockStartPos;
  764. }
  765. if (blockCode == (int)QspStatementType.ElseIf)
  766. {
  767. if (controlBlock == (int)ControlBlockType.ML_If)
  768. {
  769. controlBlock = (int)ControlBlockType.ElseIfCondition;
  770. debugText += "<ElseIfCondition> ";
  771. lastIfPos = blockStartPos;
  772. }
  773. else
  774. {
  775. SubmitError("ELSEIF без IF", lineNum);
  776. return false;
  777. }
  778. }
  779. if (blockCode == (int)QspStatementType.Else)
  780. {
  781. if (controlBlock == (int)ControlBlockType.ML_If)
  782. {
  783. if (firstSymbolPos == blockStartPos)
  784. {
  785. if ((blockStartPos + block.Length == line.Length) || (line.Substring(blockStartPos + block.Length).Trim(WhiteSpace).Equals(":")))
  786. {
  787. controlBlock = (int)ControlBlockType.ML_Else;
  788. ControlStack.Pop();
  789. ControlLine cline;
  790. cline.controlBlock = ControlBlockType.ML_Else;
  791. cline.line = lineNum;
  792. ControlStack.Push(cline);
  793. }
  794. else
  795. {
  796. SubmitError("An operator cannot be placed after multiline ELSE", lineNum);
  797. return false;
  798. }
  799. }
  800. else
  801. {
  802. SubmitError("Multiline ELSE should be at the beginning of the line", lineNum);
  803. return false;
  804. }
  805. }
  806. else
  807. {
  808. if (controlBlock == (int)ControlBlockType.SL_Act)
  809. {
  810. if (groupInnerCounter > 0)
  811. {
  812. if ((ControlStack.Peek().controlBlock == ControlBlockType.SL_If) && (ControlStack.Peek().line == lineNum))
  813. {
  814. if (blockGroupStarted)
  815. {
  816. blockGroupCompleted = true;
  817. }
  818. }
  819. else
  820. {
  821. SubmitError("ELSE without IF", lineNum);
  822. return false;
  823. }
  824. }
  825. else
  826. {
  827. SubmitError("Invalid notation of single line ACT", lineNum);
  828. return false;
  829. }
  830. }
  831. else if (controlBlock == (int)ControlBlockType.SL_If)
  832. {
  833. if (blockGroupStarted)
  834. {
  835. blockGroupCompleted = true;
  836. }
  837. else if (groupInnerCounter == 0)
  838. {
  839. SubmitError("After single line IF has to be any operators before ELSE", lineNum);
  840. return false;
  841. }
  842. }
  843. else
  844. {
  845. SubmitError("ELSE without IF", lineNum);
  846. return false;
  847. }
  848. //Это правильный ELSE
  849. if (blockStartPos + block.Length < line.Length)
  850. {
  851. string restLine = line.Substring(blockStartPos + block.Length);
  852. if (restLine.Trim(WhiteSpace).StartsWith(":"))
  853. {
  854. pos += restLine.IndexOf(':') + 1;
  855. }
  856. }
  857. ControlStack.Pop();
  858. controlBlock = (int)ControlBlockType.SL_Else;
  859. groupInnerCounter = 0;
  860. }
  861. skip = true;
  862. }
  863. if (blockCode == (int)QspStatementType.End)
  864. {
  865. if (ControlStack.Count > 0)
  866. {
  867. ControlStack.Pop();
  868. if (ControlStack.Count > 0)
  869. {
  870. ControlLine cline = ControlStack.Peek();
  871. controlBlock = (int)cline.controlBlock;
  872. }
  873. else
  874. {
  875. controlBlock = (int)ControlBlockType.None;
  876. }
  877. }
  878. else
  879. {
  880. SubmitError("Redundant END", lineNum);
  881. return false;
  882. }
  883. skip = true;
  884. }
  885. if (!skip)
  886. {
  887. if (!blockGroupStarted)
  888. {
  889. blockGroupStarted = true;
  890. groupInnerCounter++;
  891. if (singleBlockGroup)
  892. {
  893. singleBlockGroup = false;
  894. blockGroupCompleted = true;
  895. }
  896. }
  897. if (quotedTextCompleted)
  898. {
  899. blockGroup.Add(quotedText);
  900. blockInGroupIsText.Add(true);
  901. quotedTextCompleted = false;
  902. }
  903. else
  904. {
  905. if ((blockCode == (int)QspStatementType.Unknown) && (block.Length > 1))
  906. {
  907. //Обрабатываем попытки "склеить" некоторые последовательности символов
  908. string first = block.Substring(0, 1);
  909. if (first.Equals("*"))
  910. {
  911. //Если была неудачная попытка прочесть *NL, *P, и т.д., "разделяем" блок на части
  912. blockGroup.Add(first);
  913. blockInGroupIsText.Add(false);
  914. block = block.Substring(1);
  915. }
  916. }
  917. blockGroup.Add(block);
  918. blockInGroupIsText.Add(false);
  919. }
  920. if (appendDelimiter)
  921. {
  922. blockGroup.Add(delimiterToAppend);
  923. blockInGroupIsText.Add(false);
  924. }
  925. if (blockGroupStarted && (pos == line.Length - 1))
  926. {
  927. blockGroupCompleted = true;
  928. }
  929. }
  930. block = "";
  931. blockCompleted = false;
  932. blockStarted = false;
  933. }
  934. if (blockGroupCompleted)
  935. {
  936. //Разбор аргументов
  937. if (blockGroup.Count == 0)
  938. {
  939. SubmitError("Internal error of the analyzer! Empty block!", lineNum);
  940. return false;
  941. }
  942. if (!CheckBlockGroup(blockGroup, blockInGroupIsText))
  943. return false;
  944. blockGroup.Clear();
  945. blockInGroupIsText.Clear();
  946. blockGroupStarted = false;
  947. blockGroupCompleted = false;
  948. }
  949. pos++;
  950. }
  951. //Строка закончилась
  952. if (bracketLevel>0)
  953. {
  954. SubmitError("Redundant bracket \"(\"", lineNum);
  955. return false;
  956. }
  957. if (controlBlock == (int)ControlBlockType.IfCondition)
  958. {
  959. SubmitError("IF without \":\"", lineNum);
  960. return false;
  961. }
  962. if (controlBlock == (int)ControlBlockType.ActCondition)
  963. {
  964. SubmitError("ACT without \":\"", lineNum);
  965. return false;
  966. }
  967. if ((controlBlock == (int)ControlBlockType.SL_Act) || (controlBlock == (int)ControlBlockType.SL_If) || (controlBlock == (int)ControlBlockType.SL_Else))
  968. {
  969. if (groupInnerCounter > 0)
  970. {
  971. while ((ControlStack.Count > 0) && (ControlStack.Peek().controlBlock == ControlBlockType.SL_If))
  972. ControlStack.Pop();
  973. if (ControlStack.Count > 0)
  974. {
  975. ControlLine cline = ControlStack.Peek();
  976. controlBlock = (int)cline.controlBlock;
  977. }
  978. else
  979. {
  980. controlBlock = (int)ControlBlockType.None;
  981. }
  982. }
  983. else if (controlBlock == (int)ControlBlockType.SL_Act)
  984. {
  985. SubmitError("Invalid notation of single line ACT", lineNum);
  986. return false;
  987. }
  988. else if (controlBlock == (int)ControlBlockType.SL_If)
  989. {
  990. SubmitError("Invalid notation of single line IF", lineNum);
  991. return false;
  992. }
  993. else if (controlBlock == (int)ControlBlockType.SL_Else)
  994. {
  995. SubmitError("In single line IF has to be any operators after ELSE", lineNum);
  996. return false;
  997. }
  998. }
  999. //для отладки
  1000. if (line.Length > 0)
  1001. {
  1002. debugText += Environment.NewLine;
  1003. }
  1004. if (currentRoot)
  1005. {
  1006. //Вычисляем уровень вложенности(для утилиты форматирования кода)
  1007. int stackSize = ControlStack.Count;
  1008. int level = 0;
  1009. if (stackSize > 0)
  1010. {
  1011. endIndentLevel = stackSize;
  1012. ControlLine cline = ControlStack.Peek();
  1013. int b = (int)cline.controlBlock;
  1014. bool openingLine = cline.line == currentLine;
  1015. if (openingLine && ((b == (int)ControlBlockType.ML_Act) || (b == (int)ControlBlockType.ML_If)))
  1016. {
  1017. level = startIndentLevel;
  1018. }
  1019. else if (openingLine && (b == (int)ControlBlockType.ML_Else))
  1020. {
  1021. level = startIndentLevel - 1;
  1022. }
  1023. else
  1024. {
  1025. level = endIndentLevel;
  1026. }
  1027. }
  1028. location_codeline_level.Add(currentLine, level);
  1029. }
  1030. }
  1031. //Проверка на незакрытые в конце локации многострочные IF и ACT
  1032. if (ControlStack.Count > 0)
  1033. {
  1034. ControlLine cline = ControlStack.Pop();
  1035. if ((cline.controlBlock == ControlBlockType.ML_If) || (cline.controlBlock == ControlBlockType.ML_Else))
  1036. {
  1037. SubmitError("Multi line IF without END", cline.line);
  1038. return false;
  1039. }
  1040. else
  1041. {
  1042. SubmitError("Multi line ACT without END", cline.line);
  1043. return false;
  1044. }
  1045. }
  1046. AddLocationLink(m_name, true, m_start);
  1047. return true;
  1048. }
  1049. bool CheckBlockGroup(List<string> blockGroup, List<bool> blockInGroupIsText)
  1050. {
  1051. //Разбор аргументов для операторов ACT, IF, прочих операторов и функций.
  1052. string pomvarstr1;
  1053. string pomvarstr2;
  1054. bool iifpresent;
  1055. int blockCode = qspGetStatCode(blockGroup.ToArray()[0]);
  1056. if (blockInGroupIsText[0])
  1057. blockCode = (int)QspStatementType.Unknown;
  1058. bool isSetOp = blockCode == (int)QspStatementType.Set;
  1059. if ((blockCode == (int)QspStatementType.Unknown) || isSetOp)
  1060. {
  1061. //Это присваивание?
  1062. int setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "=");
  1063. if (setpos == INVALID_INDEX)
  1064. setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "+=");
  1065. if (setpos == INVALID_INDEX)
  1066. setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "-=");
  1067. if (isSetOp && (setpos == INVALID_INDEX))
  1068. {
  1069. SubmitError("Not found the char \"=\"", currentLine);
  1070. return false;
  1071. }
  1072. if (setpos != INVALID_INDEX)
  1073. {
  1074. //Присваивание
  1075. if ((setpos == 0) || (isSetOp && (setpos == 1)))
  1076. {
  1077. SubmitError("The name of a variable before the character \"=\" is not specified!", currentLine);
  1078. return false;
  1079. }
  1080. int last = blockGroup.Count - 1;
  1081. if (setpos==last)
  1082. {
  1083. SubmitError("It should be a value after char \"=\"", currentLine);
  1084. return false;
  1085. }
  1086. //Проверяем левую часть
  1087. int start = 0;
  1088. if (isSetOp)
  1089. start = 1;
  1090. int count = setpos - start;
  1091. List<string> args = new List<string>();
  1092. List<bool> types = new List<bool>();
  1093. args = blockGroup.GetRange(start, count);
  1094. types = blockInGroupIsText.GetRange(start, count);
  1095. if (!CheckLeftAssign(args, types))
  1096. return false;
  1097. string assignedVarName = args[0];
  1098. //Проверяем правую часть
  1099. start = setpos + 1;
  1100. count = last - start + 1;
  1101. args = blockGroup.GetRange(start, count);
  1102. types = blockInGroupIsText.GetRange(start, count);
  1103. if (!CheckExpression(args, types))
  1104. return false;
  1105. //Засчитываем присваивание некоторым переменным как обращение к локации
  1106. if ((count == 1) && types[0] && ListContainsIgnoreCase(callerVariables, assignedVarName))
  1107. {
  1108. AddLocationLink(args[0], false, true);
  1109. }
  1110. }
  1111. else
  1112. {
  1113. //Если оператор неизвестен, пытаемся разобрать выражение
  1114. if (!CheckExpression(blockGroup, blockInGroupIsText))
  1115. return false;
  1116. //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
  1117. if ((blockGroup.Count >= 1) && (blockInGroupIsText[0]))
  1118. {
  1119. pomvarstr1 = "";
  1120. pomvarstr2 = "";
  1121. iifpresent = false;
  1122. for (int ibc = 0; ibc < blockGroup.Count; ibc++)
  1123. {
  1124. if (blockGroup[Math.Min(ibc + 1, blockGroup.Count-1)] != "iif")
  1125. {
  1126. pomvarstr1 = pomvarstr1 + blockGroup[ibc];
  1127. pomvarstr2 = pomvarstr2 + blockGroup[ibc];
  1128. }
  1129. else
  1130. {
  1131. iifpresent = true;
  1132. while (blockGroup[ibc] != ",")
  1133. {
  1134. ibc++;
  1135. }
  1136. ibc++;
  1137. pomvarstr1 = pomvarstr1 + blockGroup[ibc];
  1138. ibc++;
  1139. ibc++;
  1140. pomvarstr2 = pomvarstr2 + blockGroup[ibc];
  1141. ibc++;
  1142. ibc++;
  1143. }
  1144. }
  1145. ParseExecInOutputText(pomvarstr1);
  1146. if (iifpresent)
  1147. ParseExecInOutputText(pomvarstr2);
  1148. }
  1149. }
  1150. }
  1151. else if ((blockCode == (int)QspStatementType.If) || (blockCode == (int)QspStatementType.ElseIf))
  1152. {
  1153. int start = 1;
  1154. int count = blockGroup.Count - 1;
  1155. if (count > 0)
  1156. {
  1157. List<string> args = blockGroup.GetRange(start, count);
  1158. List<bool> types = blockInGroupIsText.GetRange(start, count);
  1159. if (!CheckExpression(args, types))
  1160. return false;
  1161. }
  1162. else
  1163. {
  1164. if (blockCode == (int)QspStatementType.If)
  1165. {
  1166. SubmitError("Operator IF without condition", currentLine);
  1167. }
  1168. else
  1169. {
  1170. SubmitError("Operator ELSEIF without condition", currentLine);
  1171. }
  1172. return false;
  1173. }
  1174. }
  1175. else
  1176. {
  1177. //Если оператор известен, проверяем его аргументы.
  1178. int count = blockGroup.Count - 1;
  1179. List<string> args = new List<string>();
  1180. List<bool> types = new List<bool>();
  1181. if (count > 0)
  1182. {
  1183. args = blockGroup.GetRange(1, count);
  1184. types = blockInGroupIsText.GetRange(1, count);
  1185. }
  1186. if (!CheckStatementArgs(blockCode, args, types))
  1187. return false;
  1188. }
  1189. //Проверяем подвыражения вида <<$var>> в любых строках
  1190. for (int i = 0; i < blockGroup.Count; i++)
  1191. {
  1192. if (blockInGroupIsText[i])
  1193. {
  1194. if (!ParseSubExpressions(blockGroup[i]))
  1195. return false;
  1196. }
  1197. }
  1198. return true;
  1199. }
  1200. bool CheckStatementArgs(int code, List<string> argsSrc, List<bool> typesSrc)
  1201. {
  1202. int count = argsSrc.Count;
  1203. List<string> args = new List<string>();
  1204. List<bool> types = new List<bool>();
  1205. if (count > 0)
  1206. {
  1207. if ((count > 1) && argsSrc.ToArray()[0].Equals("(") && !typesSrc.ToArray()[0] &&
  1208. argsSrc.ToArray()[count - 1].Equals(")") && !typesSrc.ToArray()[count - 1])
  1209. {
  1210. //Игнорируем одну пару скобок по краям
  1211. args = argsSrc.GetRange(1, count - 2);
  1212. types = typesSrc.GetRange(1, count - 2);
  1213. }
  1214. else
  1215. {
  1216. args = argsSrc.GetRange(0, count);
  1217. types = typesSrc.GetRange(0, count);
  1218. }
  1219. }
  1220. count = args.Count;
  1221. if ((count >= 1) && types[0])
  1222. {
  1223. //Отмечаем в списке явные ссылки на локации
  1224. if ((code == (int)QspStatementType.GoSub) || (code == (int)QspStatementType.GoTo) ||
  1225. (code == (int)QspStatementType.XGoTo))
  1226. {
  1227. AddLocationLink(args[0], false, true);
  1228. }
  1229. //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
  1230. else if ((code == (int)QspStatementType.P) || (code == (int)QspStatementType.PL) ||
  1231. (code == (int)QspStatementType.NL) || (code == (int)QspStatementType.MP) ||
  1232. (code == (int)QspStatementType.MPL) || (code == (int)QspStatementType.MNL))
  1233. {
  1234. ParseExecInOutputText(args[0]);
  1235. }
  1236. //Отмечаем в списке добавленные предметы
  1237. else if (code == (int)QspStatementType.AddObj)
  1238. {
  1239. AddObj(args[0], true, false);
  1240. }
  1241. //Отмечаем в списке удаленные предметы
  1242. else if (code == (int)QspStatementType.DelObj)
  1243. {
  1244. AddObj(args[0], false, true);
  1245. }
  1246. //Отмечаем в списке добавленные действия
  1247. else if (code == (int)QspStatementType.Act)
  1248. {
  1249. AddAct(args[0], true, false);
  1250. }
  1251. //Отмечаем в списке удаленные действия
  1252. else if (code == (int)QspStatementType.DelAct)
  1253. {
  1254. AddAct(args[0], false, true);
  1255. }
  1256. }
  1257. int minArgCount = qspStats[code].MinArgsCount;
  1258. int maxArgCount = qspStats[code].MaxArgsCount;
  1259. int argCount = 0;
  1260. int curIndex = 0;
  1261. List<string> expr = new List<string>();
  1262. if (count > 0)
  1263. {
  1264. while (true)
  1265. {
  1266. if (argCount == maxArgCount)
  1267. {
  1268. SubmitError("Too many arguments for the operator", currentLine);
  1269. return false;
  1270. }
  1271. int index = FindInTopBracketLevel(args, types, ",", curIndex);
  1272. if (index != INVALID_INDEX)
  1273. {
  1274. if (index > curIndex)
  1275. {
  1276. if (!CheckExpression(args.GetRange(curIndex, index - curIndex), types.GetRange(curIndex, index - curIndex)))
  1277. return false;
  1278. }
  1279. else
  1280. {
  1281. SubmitError("Argument can not be empty", currentLine);
  1282. return false;
  1283. }
  1284. }
  1285. else
  1286. {
  1287. if (!CheckExpression(args.GetRange(curIndex, count - curIndex), types.GetRange(curIndex, count - curIndex)))
  1288. return false;
  1289. }
  1290. argCount++;
  1291. if (index == INVALID_INDEX)
  1292. break;
  1293. curIndex = index + 1;
  1294. if (curIndex == count)
  1295. {
  1296. SubmitError("Argument can not be empty", currentLine);
  1297. return false;
  1298. }
  1299. }
  1300. }
  1301. if (argCount < minArgCount)
  1302. {
  1303. SubmitError("The operator requires more arguments", currentLine);
  1304. return false;
  1305. }
  1306. return true;
  1307. }
  1308. bool CheckExpression(List<string> args, List<bool> types)
  1309. {
  1310. //Проверка выражения
  1311. int[] opStack = new int[QSP_STACKSIZE];
  1312. int[] argStack = new int[QSP_STACKSIZE];
  1313. bool waitForOperator = false;
  1314. int opCode, itemsCount = 0, opSp = -1, argSp = -1;
  1315. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Start))
  1316. return false;
  1317. int argIndex = 0;
  1318. while (argIndex <= args.Count)
  1319. {
  1320. String s = "";
  1321. if (argIndex < args.Count)
  1322. s = args[argIndex];
  1323. if (waitForOperator)
  1324. {
  1325. opCode = qspGetFunctionCode(s, false);
  1326. String nextArg = "";
  1327. bool nextArgIsString = false;
  1328. bool hasNextArg = argIndex + 1 < args.Count;
  1329. if (hasNextArg)
  1330. {
  1331. nextArg = args[argIndex + 1];
  1332. nextArgIsString = types[argIndex + 1];
  1333. }
  1334. if (opCode == (int)QspFunctionType.Unknown || opCode >= (int)QspFunctionType.First_Function)
  1335. {
  1336. SubmitError("Unknown action in the expression", currentLine);
  1337. break;
  1338. }
  1339. if (((opCode == (int)QspFunctionType.And) || (opCode == (int)QspFunctionType.Or) || (opCode == (int)QspFunctionType.Mod)) &&
  1340. !(hasNextArg && (nextArgIsString || nextArg.Equals("(") || (nextArg.IndexOfAny(Delimiters) == INVALID_INDEX)))
  1341. )
  1342. {
  1343. SubmitError("Syntax error", currentLine);
  1344. break;
  1345. }
  1346. bool bError = false;
  1347. while (qspOps[opCode].Priority <= qspOps[opStack[opSp]].Priority && qspOps[opStack[opSp]].Priority != 127)
  1348. {
  1349. if (opStack[opSp] >= (int)QspFunctionType.First_Function) ++argStack[argSp];
  1350. if (!qspAppendToCompiled(ref itemsCount))
  1351. {
  1352. bError = true;
  1353. break;
  1354. }
  1355. if (--opSp < 0 || --argSp < 0)
  1356. {
  1357. SubmitError("Syntax error", currentLine);
  1358. bError = true;
  1359. break;
  1360. }
  1361. }
  1362. if (bError)
  1363. break;
  1364. switch (opCode)
  1365. {
  1366. case (int)QspFunctionType.End:
  1367. if (opSp > 0)
  1368. {
  1369. SubmitError("Closing bracket not found", currentLine);
  1370. bError = true;
  1371. break;
  1372. }
  1373. return itemsCount > 0;
  1374. case (int)QspFunctionType.CloseBracket:
  1375. if (opStack[opSp] != (int)QspFunctionType.OpenBracket)
  1376. {
  1377. SubmitError("Opening bracket not found", currentLine);
  1378. bError = true;
  1379. break;
  1380. }
  1381. opCode = opStack[--opSp];
  1382. if (opCode >= (int)QspFunctionType.First_Function)
  1383. {
  1384. if (argStack[argSp] + 1 < qspOps[opCode].MinArgsCount || argStack[argSp] + 1 > qspOps[opCode].MaxArgsCount)
  1385. {
  1386. SubmitError("Invalid number of arguments", currentLine);
  1387. bError = true;
  1388. }
  1389. }
  1390. else
  1391. --argSp;
  1392. break;
  1393. case (int)QspFunctionType.Comma:
  1394. if ((opSp > 0) && opStack[opSp - 1] >= (int)QspFunctionType.First_Function)
  1395. {
  1396. if (++argStack[argSp] > qspOps[opStack[opSp - 1]].MaxArgsCount)
  1397. {
  1398. SubmitError("Invalid number of arguments", currentLine);
  1399. bError = true;
  1400. break;
  1401. }
  1402. }
  1403. else
  1404. {
  1405. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Comma))
  1406. {
  1407. bError = true;
  1408. break;
  1409. }
  1410. }
  1411. waitForOperator = false;
  1412. break;
  1413. default:
  1414. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
  1415. {
  1416. bError = true;
  1417. break;
  1418. }
  1419. waitForOperator = false;
  1420. break;
  1421. }
  1422. if (bError)
  1423. break;
  1424. }
  1425. else
  1426. {
  1427. if ((argIndex < args.Count) && !types[argIndex] && IsNumber(s))
  1428. {
  1429. if (opStack[opSp] == (int)QspFunctionType.Minus)
  1430. {
  1431. --opSp;
  1432. --argSp;
  1433. }
  1434. if (!qspAppendToCompiled(ref itemsCount))
  1435. break;
  1436. waitForOperator = true;
  1437. }
  1438. // I added this piece of code (next 7 lines) so the program could detect function call and the first argument -name of the function / location
  1439. // I do not assure that I did it in a proper place, but it seems that it works.
  1440. else if ((opStack[1] == (int)QspFunctionType.Func) && (argIndex == 2))
  1441. {
  1442. AddLocationLink(s, false, true);
  1443. }
  1444. else if ((opStack[1] == (int)QspFunctionType.Func) && (argIndex == 3) && (s == ","))
  1445. {
  1446. }
  1447. else if ((argIndex < args.Count) && types[argIndex])
  1448. {
  1449. if (!qspAppendToCompiled(ref itemsCount))
  1450. break;
  1451. waitForOperator = true;
  1452. }
  1453. else if (s.Equals("+"))
  1454. {
  1455. }
  1456. else if (s.Equals("-"))
  1457. {
  1458. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Minus))
  1459. break;
  1460. }
  1461. else if (s.Equals("("))
  1462. {
  1463. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.OpenBracket))
  1464. break;
  1465. }
  1466. else if (s.Equals(")"))
  1467. {
  1468. opCode = opStack[opSp];
  1469. if (opCode != (int)QspFunctionType.OpenBracket)
  1470. {
  1471. if (opCode >= (int)QspFunctionType.First_Function)
  1472. SubmitError("Invalid number of arguments", currentLine);
  1473. else
  1474. SubmitError("Syntax error", currentLine);
  1475. break;
  1476. }
  1477. opCode = opStack[--opSp];
  1478. if (opCode < (int)QspFunctionType.First_Function)
  1479. {
  1480. SubmitError("Syntax error", currentLine);
  1481. break;
  1482. }
  1483. if (qspOps[opCode].MinArgsCount > argSp)
  1484. {
  1485. SubmitError("Invalid number of arguments", currentLine);
  1486. break;
  1487. }
  1488. if (!qspAppendToCompiled(ref itemsCount))
  1489. break;
  1490. --opSp;
  1491. --argSp;
  1492. waitForOperator = true;
  1493. }
  1494. else if ((argIndex < args.Count) && s.IndexOfAny(Delimiters) != 0)
  1495. {
  1496. if (s.IndexOfAny(Delimiters) != INVALID_INDEX)
  1497. {
  1498. SubmitError("Internal error of the analyzer: Invalid characters in the variable name", currentLine);
  1499. break;
  1500. }
  1501. opCode = qspGetFunctionCode(s, true);
  1502. if (opCode >= (int)QspFunctionType.First_Function)
  1503. {
  1504. if ((args.Count - argIndex > 1) && (args[argIndex + 1].Equals("(") && !types[argIndex + 1]))
  1505. {
  1506. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
  1507. break;
  1508. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.OpenBracket))
  1509. break;
  1510. argIndex++;
  1511. --argSp;
  1512. }
  1513. else if (qspOps[opCode].MinArgsCount < 2)
  1514. {
  1515. if (qspOps[opCode].MinArgsCount > 0)
  1516. {
  1517. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
  1518. break;
  1519. }
  1520. else
  1521. {
  1522. if (!qspAppendToCompiled(ref itemsCount))
  1523. break;
  1524. waitForOperator = true;
  1525. }
  1526. }
  1527. else
  1528. {
  1529. SubmitError("Brackets not found", currentLine);
  1530. break;
  1531. }
  1532. }
  1533. else
  1534. {
  1535. int optArgsCount = 0;
  1536. //Проверяем выражение(индекс массива)
  1537. if ((args.Count - argIndex > 1) && (args[argIndex + 1].Equals("[") && !types[argIndex + 1]))
  1538. {
  1539. int optIndex = argIndex + 2;
  1540. int level = 1;
  1541. bool bFound = false;
  1542. while (optIndex < args.Count)
  1543. {
  1544. if (args[optIndex].Equals("[") && !types[optIndex])
  1545. {
  1546. level++;
  1547. }
  1548. else if (args[optIndex].Equals("]") && !types[optIndex])
  1549. {
  1550. level--;
  1551. if (level == 0)
  1552. {
  1553. bFound = true;
  1554. break;
  1555. }
  1556. }
  1557. optIndex++;
  1558. }
  1559. if (level > 0)
  1560. {
  1561. SubmitError("Unclosed parenthesis \"[\"", currentLine);
  1562. break;
  1563. }
  1564. if (bFound)
  1565. optArgsCount = optIndex - argIndex;
  1566. }
  1567. List<string> subArgs = args.GetRange(argIndex, optArgsCount + 1);
  1568. List<bool> subTypes = types.GetRange(argIndex, optArgsCount + 1);
  1569. if (!CheckVariable(subArgs, subTypes, false))
  1570. break;
  1571. argIndex += optArgsCount;
  1572. if (!qspAppendToCompiled(ref itemsCount))
  1573. break;
  1574. waitForOperator = true;
  1575. }
  1576. }
  1577. else
  1578. {
  1579. if (opStack[opSp] >= (int)QspFunctionType.First_Function)
  1580. SubmitError("Invalid number of arguments", currentLine);
  1581. else
  1582. SubmitError("Syntax error", currentLine);
  1583. break;
  1584. }
  1585. }
  1586. argIndex++;
  1587. }
  1588. return false;
  1589. }
  1590. bool CheckVariable(List<string> args, List<bool> types, bool assignment)
  1591. {
  1592. //Проверка имени переменной
  1593. if ((args.Count == 0) || (args[0].Length == 0) || types[0])
  1594. {
  1595. SubmitError("Internal error of the analyzer: empty name of variable!", currentLine);
  1596. return false;
  1597. }
  1598. string name = args[0];
  1599. int code1 = qspGetStatCode(name);
  1600. int code2 = qspGetFunctionCode(name, true);
  1601. if ((code1 != (int)QspStatementType.Unknown) || (code2 != (int)QspFunctionType.Unknown))
  1602. {
  1603. SubmitError("QSP Keyword \"" + name + "\" cannot be used as a variable name", currentLine);
  1604. return false;
  1605. }
  1606. //Проверяем имя переменной на валидность
  1607. //В имени переменной разрешены все символы, кроме DELIMS и цифры в начале имени
  1608. //Перед именем переменной может находиться префикс "$"
  1609. string checkName = name;
  1610. if (checkName.StartsWith("$"))
  1611. checkName = checkName.Substring(1);
  1612. // $ =
  1613. if (checkName.Length == 0)
  1614. {
  1615. SubmitError("Invalid variable name \"" + name + "\"", currentLine);
  1616. return false;
  1617. }
  1618. // 1asd =
  1619. if (checkName.Substring(0, 1).IndexOfAny(Digits) != INVALID_INDEX)
  1620. {
  1621. SubmitError("Variable name \"" + name + "\" cannot start with a digit", currentLine);
  1622. return false;
  1623. }
  1624. // /asd =
  1625. if (checkName.IndexOfAny(Delimiters) != INVALID_INDEX)
  1626. {
  1627. SubmitError("Invalid symbols in the name of the variable \"" + name + "\"", currentLine);
  1628. return false;
  1629. }
  1630. //Проверяем переменную на "смешанные раскладки"
  1631. if ((checkName.IndexOfAny(LatinLetters) != INVALID_INDEX) && (checkName.IndexOfAny(RussianLetters) != INVALID_INDEX))
  1632. {
  1633. SubmitWarning("English and Russian symbols are used simultaneously in the name of varible \"" + name + "\" , possibly a typo", currentLine);
  1634. }
  1635. //Проверяем выражение(индекс массива)
  1636. if (args.Count > 1)
  1637. {
  1638. if (args.Count > 2 && args[1].Equals("[") && !types[1] &&
  1639. args[args.Count - 1].Equals("]") && !types[args.Count - 1])
  1640. {
  1641. int start = 2;
  1642. int count = args.Count - 3;
  1643. if (count > 0)
  1644. {
  1645. List<string> argsCut = args.GetRange(start, count);
  1646. List<bool> typesCut = types.GetRange(start, count);
  1647. if (!CheckExpression(argsCut, typesCut))
  1648. return false;
  1649. }
  1650. }
  1651. else
  1652. {
  1653. SubmitError("Invalid expression", currentLine);
  1654. return false;
  1655. }
  1656. }
  1657. //Сохраняем имя переменной в глобальном списке
  1658. if (!assignment)
  1659. {
  1660. bool usedBySystem = ListContainsIgnoreCase(systemVariables, name);
  1661. AddVar(name, usedBySystem, true);
  1662. }
  1663. return true;
  1664. }
  1665. bool CheckLeftAssign(List<string> args, List<bool> types)
  1666. {
  1667. //Проверка имени переменной(слева от знака "=" в операции присваивания)
  1668. if ((args.Count == 0) || (args[0].Length == 0) || types[0])
  1669. {
  1670. //Текстовая строка
  1671. SubmitError("Name of the variable should be before char \"=\" in the assignment operation", currentLine);
  1672. return false;
  1673. }
  1674. if (!CheckVariable(args, types, true))
  1675. return false;
  1676. //Сохраняем имя переменной в глобальном списке
  1677. bool usedBySystem = ListContainsIgnoreCase(systemVariables, args[0]);
  1678. AddVar(args[0], true, usedBySystem);
  1679. return true;
  1680. }
  1681. int FindInTopBracketLevel(List<string> args, List<bool> types, string what)
  1682. {
  1683. return FindInTopBracketLevel(args, types, what, 0);
  1684. }
  1685. int FindInTopBracketLevel(List<string> args, List<bool> types, string what, int startIndex)
  1686. {
  1687. //Ищем знак "=" или запятую вне скобок
  1688. int bracketLevel = 0;
  1689. for (int i = startIndex; i < args.Count; i++)
  1690. {
  1691. if (types[i])
  1692. continue;
  1693. string block = args[i];
  1694. if (block.Equals("("))
  1695. {
  1696. bracketLevel++;
  1697. }
  1698. else if (block.Equals(")"))
  1699. {
  1700. bracketLevel--;
  1701. }
  1702. else if (block.Equals(what) && (bracketLevel == 0))
  1703. {
  1704. return i;
  1705. }
  1706. }
  1707. return INVALID_INDEX;
  1708. }
  1709. void ParseExecInOutputText(string text)
  1710. {
  1711. //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
  1712. int pos = 0;
  1713. //Строим "карту" подвыражений.
  1714. //Если подвыражения в строке содержат ошибки, то разбирать теги нет смысла.
  1715. List<int> subExpMap = new List<int>();
  1716. if (!ParseSubExpressions(text, ref subExpMap))
  1717. return;
  1718. int subExpSkipped = 0;
  1719. while (pos < text.Length)
  1720. {
  1721. pos = text.IndexOf("<a", pos);
  1722. if (pos == INVALID_INDEX)
  1723. break;
  1724. if (subExpMap.Count / 2 > subExpSkipped)
  1725. {
  1726. int subExpStartPos = subExpMap[subExpSkipped * 2];
  1727. int subExpEndPos = subExpMap[subExpSkipped * 2 + 1];
  1728. if (subExpStartPos == pos)
  1729. {
  1730. //Пропускаем подвыражения вне тегов
  1731. subExpSkipped++;
  1732. pos = subExpEndPos + 1;
  1733. continue;
  1734. }
  1735. }
  1736. //Разбираем содержимое угловых скобок
  1737. //Внутри HTML-тега кавычки экранируются не через дублирование, как в QSP, а через "\",
  1738. //причем экранирование требуется только внутри окавыченной строки.
  1739. List<string> blockGroup = new List<string>();
  1740. List<bool> blockInGroupIsText = new List<bool>();
  1741. int firstBlockPosition = INVALID_INDEX;
  1742. string quotedText = "";
  1743. string block = "";
  1744. bool tagClosed = false;
  1745. bool quotedTextCompleted = false;
  1746. bool blockCompleted = false;
  1747. pos++;
  1748. int startPos = pos;
  1749. if ((pos < text.Length) && (text[pos] == '/'))
  1750. startPos++;
  1751. int tagQuote = (int)QuoteType.None;
  1752. while (!tagClosed && (pos < text.Length))
  1753. {
  1754. if (subExpMap.Count / 2 > subExpSkipped)
  1755. {
  1756. int subExpStartPos = subExpMap[subExpSkipped * 2];
  1757. int subExpEndPos = subExpMap[subExpSkipped * 2 + 1];
  1758. if (subExpStartPos == pos)
  1759. {
  1760. //Пропускаем подвыражения вне тегов
  1761. subExpSkipped++;
  1762. string subExpText = text.Substring(pos, subExpEndPos - pos + 1);
  1763. if (tagQuote == (int)QuoteType.None)
  1764. block += subExpText;
  1765. else
  1766. quotedText += subExpText;
  1767. pos = subExpEndPos + 1;
  1768. continue;
  1769. }
  1770. }
  1771. char c2 = text[pos];
  1772. if (tagQuote != (int)QuoteType.None)
  1773. {
  1774. //Апостроф либо кавычка
  1775. if (((tagQuote == (int)QuoteType.Single) && (c2 == '\'')) ||
  1776. ((tagQuote == (int)QuoteType.Double) && (c2 == '"')))
  1777. {
  1778. if ((pos - 1 > 0) && (text[pos - 1] == '\\'))
  1779. {
  1780. //Экранированный апостроф либо кавычка
  1781. if (!quotedTextCompleted)
  1782. quotedText = quotedText.Substring(0, quotedText.Length - 1) + c2;
  1783. }
  1784. else
  1785. {
  1786. tagQuote = (int)QuoteType.None;
  1787. quotedTextCompleted = true;
  1788. }
  1789. }
  1790. else if (!quotedTextCompleted)
  1791. {
  1792. quotedText += c2;
  1793. }
  1794. }
  1795. else if (c2 == '>')
  1796. {
  1797. tagClosed = true;
  1798. }
  1799. else if ((block.Length == 0) && (c2 == '\''))
  1800. {
  1801. tagQuote = (int)QuoteType.Single;
  1802. if (text[pos + 1] == '\'')
  1803. {
  1804. pos++;
  1805. }
  1806. }
  1807. else if ((block.Length == 0) && (c2 == '"'))
  1808. {
  1809. tagQuote = (int)QuoteType.Double;
  1810. }
  1811. else if (c2.ToString().IndexOfAny(WhiteSpace) == 0)
  1812. {
  1813. if (block.Length > 0)
  1814. {
  1815. blockCompleted = true;
  1816. }
  1817. }
  1818. else if (c2 == '=')
  1819. {
  1820. if (block.Length > 0)
  1821. {
  1822. blockGroup.Add(block);
  1823. blockInGroupIsText.Add(false);
  1824. }
  1825. block = "=";
  1826. blockCompleted = true;
  1827. }
  1828. else
  1829. {
  1830. if (firstBlockPosition == INVALID_INDEX)
  1831. {
  1832. firstBlockPosition = pos - startPos;
  1833. }
  1834. block += c2;
  1835. }
  1836. if (tagClosed)
  1837. {
  1838. if (block.Length > 0)
  1839. blockCompleted = true;
  1840. }
  1841. if (blockCompleted)
  1842. {
  1843. blockGroup.Add(block);
  1844. blockInGroupIsText.Add(false);
  1845. blockCompleted = false;
  1846. block = "";
  1847. }
  1848. if (quotedTextCompleted)
  1849. {
  1850. blockGroup.Add(quotedText);
  1851. blockInGroupIsText.Add(true);
  1852. quotedTextCompleted = false;
  1853. quotedText = "";
  1854. }
  1855. pos++;
  1856. }
  1857. if (tagQuote == (int)QuoteType.Single)
  1858. {
  1859. SubmitWarning("Unclosed apostrophe inside the tag", currentLine);
  1860. break;
  1861. }
  1862. else if (tagQuote == (int)QuoteType.Double)
  1863. {
  1864. SubmitWarning("Unclosed quote inside the tag", currentLine);
  1865. break;
  1866. }
  1867. if (!tagClosed)
  1868. {
  1869. SubmitWarning("Unclosed tag",currentLine);
  1870. break;
  1871. }
  1872. if (firstBlockPosition > 0)
  1873. {
  1874. SubmitWarning("The name of the tag should follow immediately after the opening angle bracket, without spaces", currentLine);
  1875. break;
  1876. }
  1877. //Ищем HREF в атрибутах тега A
  1878. int hrefIndex = INVALID_INDEX;
  1879. if ((blockGroup.Count > 3) && (blockGroup[0].Equals("A", StringComparison.OrdinalIgnoreCase)) && !blockInGroupIsText[0])
  1880. {
  1881. for (int i = 1; i + 2 < blockGroup.Count; i++)
  1882. {
  1883. if (blockGroup[i].Equals("HREF", StringComparison.OrdinalIgnoreCase) && !blockInGroupIsText[i] &&
  1884. blockGroup[i + 1].Equals("=") && !blockInGroupIsText[i + 1])
  1885. {
  1886. hrefIndex = i + 2;
  1887. }
  1888. }
  1889. }
  1890. if (hrefIndex != INVALID_INDEX)
  1891. {
  1892. string hrefText = blockGroup[hrefIndex];
  1893. int execKeywordLength = "EXEC:".Length;
  1894. if (hrefText.StartsWith("EXEC:", StringComparison.OrdinalIgnoreCase) && (hrefText.Length > execKeywordLength))
  1895. {
  1896. string execText = hrefText.Substring(execKeywordLength);
  1897. List<int> subExpMapExec = new List<int>();
  1898. ParseSubExpressions(execText, ref subExpMapExec);
  1899. if (subExpMapExec.Count == 0)
  1900. {
  1901. //В EXEC не разбираем код с подвыражениями, это невозможно без интерпретации
  1902. List<string> tagLines = new List<string>(execText.Split('\n'));
  1903. bool wasRoot = currentRoot;
  1904. currentRoot = false;
  1905. ParseLocation(tagLines, currentRoot);
  1906. currentRoot = wasRoot;
  1907. }
  1908. }
  1909. }
  1910. }
  1911. }
  1912. bool ParseSubExpressions(string text)
  1913. {
  1914. List<int> dummy = null;
  1915. return ParseSubExpressions(text, ref dummy);
  1916. }
  1917. bool ParseSubExpressions(string text, ref List<int> subExpMap)
  1918. {
  1919. bool quiet = subExpMap != null;
  1920. //Разбираем подвыражения - <<$var>>
  1921. if (quiet)
  1922. subExpMap.Clear();
  1923. int pos = 0;
  1924. bool valid = true;
  1925. while (valid && pos < text.Length)
  1926. {
  1927. pos = text.IndexOf("<<", pos);
  1928. if (pos == INVALID_INDEX)
  1929. break;
  1930. if (quiet)
  1931. subExpMap.Add(pos);
  1932. //Разбираем содержимое двойных угловых скобок
  1933. string subText = "";
  1934. bool subClosed = false;
  1935. pos += 2;
  1936. int subQuote = (int)QuoteType.None;
  1937. int curlyLevel = 0;
  1938. while (pos < text.Length)
  1939. {
  1940. char c2 = text[pos];
  1941. if (subQuote == (int)QuoteType.None)
  1942. {
  1943. if ((c2 == '>') && (pos + 1 < text.Length) && (text[pos + 1] == '>') && (curlyLevel == 0))
  1944. {
  1945. subClosed = true;
  1946. break;
  1947. }
  1948. else if (c2 == '\'')
  1949. {
  1950. subQuote = (int)QuoteType.Single;
  1951. }
  1952. else if (c2 == '"')
  1953. {
  1954. subQuote = (int)QuoteType.Double;
  1955. }
  1956. else if (c2 == '{')
  1957. {
  1958. curlyLevel++;
  1959. }
  1960. else if (c2 == '}')
  1961. {
  1962. curlyLevel--;
  1963. }
  1964. }
  1965. else if (((subQuote == (int)QuoteType.Single) && (c2 == '\'')) ||
  1966. ((subQuote == (int)QuoteType.Double) && (c2 == '"')))
  1967. {
  1968. //Апостроф или кавычка
  1969. if ((pos + 1 < text.Length) && (
  1970. ((subQuote == (int)QuoteType.Single) && (text[pos + 1] == '\'')) ||
  1971. ((subQuote == (int)QuoteType.Double) && (text[pos + 1] == '"'))))
  1972. {
  1973. //Экранированный апостроф либо кавычка
  1974. }
  1975. else
  1976. {
  1977. subQuote = (int)QuoteType.None;
  1978. }
  1979. }
  1980. subText += c2;
  1981. pos++;
  1982. }
  1983. if (quiet)
  1984. {
  1985. if (subClosed)
  1986. subExpMap.Add(pos + 1);
  1987. else
  1988. subExpMap.Add(pos - 1);
  1989. }
  1990. if (subQuote == (int)QuoteType.Single)
  1991. {
  1992. if (!quiet)
  1993. SubmitError("Unclosed apostrophe in a subexpression", currentLine);
  1994. valid = false;
  1995. break;
  1996. }
  1997. else if (subQuote == (int)QuoteType.Double)
  1998. {
  1999. if (!quiet)
  2000. SubmitError("Unclosed quote in a subexpression", currentLine);
  2001. valid = false;
  2002. break;
  2003. }
  2004. else if (curlyLevel != 0)
  2005. {
  2006. if (!quiet)
  2007. SubmitError("Unclosed curly bracket in a subexpression", currentLine);
  2008. valid = false;
  2009. break;
  2010. }
  2011. if (!subClosed)
  2012. {
  2013. if (!quiet)
  2014. SubmitError("Unclosed subexpression", currentLine);
  2015. valid = false;
  2016. break;
  2017. }
  2018. if (subText.Trim(WhiteSpace).Length == 0)
  2019. {
  2020. if (!quiet)
  2021. SubmitError("Empty subexpression", currentLine);
  2022. valid = false;
  2023. break;
  2024. }
  2025. if (!quiet)
  2026. {
  2027. //Парсим подвыражение как исполняемый код.
  2028. //Для того, чтобы строка считалась именно выражением, добавляем ''+ в начало
  2029. subText = "''+" + subText;
  2030. List<string> subLines = new List<string>(subText.Split('\n'));
  2031. bool wasRoot = currentRoot;
  2032. currentRoot = false;
  2033. valid = ParseLocation(subLines, currentRoot);
  2034. currentRoot = wasRoot;
  2035. }
  2036. }
  2037. return valid;
  2038. }
  2039. }
  2040. public class QSPGameCode : Common
  2041. {
  2042. Hashtable m_LocationsByName;
  2043. List<Location> m_LocationsByOrder;
  2044. Location m_lastLocation;
  2045. public QSPGameCode()
  2046. {
  2047. m_LocationsByName = new Hashtable();
  2048. m_LocationsByOrder = new List<Location>();
  2049. m_lastLocation = null;
  2050. }
  2051. public bool ParseGame(string fileName, object sender, DoWorkEventArgs e)
  2052. {
  2053. int totalLines = 0;
  2054. StreamReader rTl = new StreamReader(fileName);
  2055. while (rTl.ReadLine() != null) { totalLines++; };
  2056. m_LocationsByName.Clear();
  2057. m_LocationsByOrder.Clear();
  2058. ClearErrors();
  2059. m_lastLocation = null;
  2060. currentLocation = "";
  2061. vars = new List<QspVariable>();
  2062. locationLinks = new List<QspLocationLink>();
  2063. objects = new List<QspObj>();
  2064. acts = new List<QspAct>();
  2065. StreamReader fi = null;
  2066. if (!OpenStreamForReading(ref fi, fileName))
  2067. {
  2068. return false;
  2069. }
  2070. string s;
  2071. int line_counter = 0;
  2072. List<string> locationCode = new List<string>();
  2073. bool inside = false;
  2074. while ((s = fi.ReadLine()) != null)
  2075. {
  2076. line_counter++;
  2077. string trimmed = s.Trim(WhiteSpace);
  2078. if ((trimmed.Length > 0) && (trimmed[0] == '#'))
  2079. {
  2080. //имя локации
  2081. string locName = trimmed.Substring(1).Trim(WhiteSpace);
  2082. if (!AddLocation(locName, line_counter))
  2083. {
  2084. fi.Close();
  2085. rTl.Close();
  2086. return false;
  2087. }
  2088. currentLocation = locName;
  2089. inside = true;
  2090. }
  2091. else if ((trimmed.Length > 38) && trimmed.StartsWith("--- ") && trimmed.EndsWith(" ---------------------------------"))
  2092. {
  2093. inside = false;
  2094. Location lastLoc = GetLastLocation();
  2095. if (lastLoc != null)
  2096. {
  2097. lastLoc.ParseLocation(locationCode, true);
  2098. locationCode.Clear();
  2099. currentLocation = "";
  2100. }
  2101. }
  2102. else
  2103. {
  2104. if (inside && GetLastLocation() != null)
  2105. locationCode.Add(s);
  2106. }
  2107. (sender as BackgroundWorker).ReportProgress(Convert.ToInt32(((double)line_counter/(double)totalLines) * 100));
  2108. if ((sender as BackgroundWorker).CancellationPending)
  2109. {
  2110. e.Cancel = true;
  2111. return true;
  2112. }
  2113. }
  2114. fi.Close();
  2115. rTl.Close();
  2116. return true;
  2117. }
  2118. public bool AddLocation(string name, int line)
  2119. {
  2120. if (name.Length <= 0)
  2121. {
  2122. SubmitError("Empty name of location", line);
  2123. return false;
  2124. }
  2125. if (m_LocationsByName.ContainsKey(name))
  2126. {
  2127. SubmitError("Location named " + name + " exist already", line);
  2128. return false;
  2129. }
  2130. Location newLoc = new Location(this, name, line, m_LocationsByOrder.Count == 0);
  2131. m_LocationsByName.Add(name, newLoc);
  2132. m_LocationsByOrder.Add(newLoc);
  2133. m_lastLocation = newLoc;
  2134. return true;
  2135. }
  2136. public Location GetLastLocation()
  2137. {
  2138. return m_lastLocation;
  2139. }
  2140. public Hashtable GetLocationsByName()
  2141. {
  2142. return m_LocationsByName;
  2143. }
  2144. public Location GetLocation(string locationName)
  2145. {
  2146. Location loc = (Location)m_LocationsByName[locationName];
  2147. return loc;
  2148. }
  2149. public bool Beautify(string fileName)
  2150. {
  2151. //Причесываем код - добавляем пробелов
  2152. StreamWriter fo = null;
  2153. if (!OpenStreamForWriting(ref fo, fileName))
  2154. return false;
  2155. for (int i = 0; i < m_LocationsByOrder.Count; i++)
  2156. {
  2157. Location loc = (Location)m_LocationsByOrder[i];
  2158. fo.WriteLine("# " + loc.GetName());
  2159. for (int j = 0; j < loc.GetCodeLinesCount(); j++)
  2160. {
  2161. string text = "";
  2162. int level = INVALID_INDEX;
  2163. loc.GetCodeLine(j, ref text, ref level);
  2164. if (level != INVALID_INDEX)
  2165. {
  2166. text = new string(' ', level * 4) + text.TrimStart(WhiteSpace);
  2167. }
  2168. fo.WriteLine(text);
  2169. }
  2170. fo.WriteLine("--- " + loc.GetName() + " ---------------------------------");
  2171. fo.WriteLine();
  2172. }
  2173. fo.Close();
  2174. return true;
  2175. }
  2176. }
  2177. }