QSPGameCode.cs 98 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302
  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 == ':') && (block == "else"))
  551. {
  552. SubmitError("ELSE with :", lineNum);
  553. return false;
  554. }
  555. else if ((c == ':') && (controlBlock == (int)ControlBlockType.ActCondition))
  556. {
  557. //Разбор аргумента
  558. if (blockStarted)
  559. blockCompleted = true;
  560. blockGroupCompleted = true;
  561. //Двоеточие после ACT
  562. if (pos == line.Length - 1)
  563. {
  564. //В конце строки - многострочный ACT
  565. if (firstSymbolPos == lastActPos)
  566. {
  567. controlBlock = (int)ControlBlockType.ML_Act;
  568. ControlLine cline;
  569. cline.line = lineNum;
  570. cline.controlBlock = ControlBlockType.ML_Act;
  571. ControlStack.Push(cline);
  572. }
  573. else
  574. {
  575. SubmitError("Multiline ACT should be placed at the beginning of the line", lineNum);
  576. return false;
  577. }
  578. }
  579. else
  580. {
  581. //Строка не заканчивается - однострочный ACT
  582. controlBlock = (int)ControlBlockType.SL_Act;
  583. groupInnerCounter = 0;
  584. }
  585. }
  586. else if (!comment && (c == '!') && !blockGroupStarted && !blockStarted)
  587. {
  588. //Начало комментария
  589. comment = true;
  590. }
  591. else if ((c == ':') && (firstSymbolPos == pos))
  592. {
  593. //Начало метки
  594. label = true;
  595. }
  596. else if (c.ToString().IndexOfAny(Delimiters) == 0)
  597. {
  598. //Особый учет для последовательностей >=, => и т.д.
  599. bool comparer = pos + 1 < line.Length;
  600. String cmp = "";
  601. if (comparer)
  602. {
  603. cmp = line.Substring(pos, 2);
  604. comparer = cmp.Equals("<=") || cmp.Equals(">=") || cmp.Equals("=>") || cmp.Equals("=<") || cmp.Equals("<>") ||
  605. cmp.Equals("+=") || cmp.Equals("-=") || cmp.Equals("*=") || cmp.Equals("/=");
  606. }
  607. if ((c == '&') && (bracketLevel == 0))
  608. {
  609. if (controlBlock == (int)ControlBlockType.IfCondition)
  610. {
  611. //В условии IF недопустимо использование "&" вне скобок
  612. SubmitError("Redundant \"&\": perhaps should be \"AND\"", lineNum);
  613. return false;
  614. }
  615. else if (controlBlock == (int)ControlBlockType.ActCondition)
  616. {
  617. //В названии ACT недопустимо использование "&" вне скобок
  618. SubmitError("Redundant \"&\"", lineNum);
  619. return false;
  620. }
  621. else
  622. {
  623. if (blockStarted)
  624. blockCompleted = true;
  625. if (blockGroupStarted)
  626. blockGroupCompleted = true;
  627. if (blockStarted && !blockGroupStarted)
  628. singleBlockGroup = true;
  629. }
  630. }
  631. else if (blockStarted && (c == ' ') && StartOfMultiWordOperator(block))
  632. {
  633. //Составной оператор - DEL ACT, DEL OBJ
  634. block += c;
  635. }
  636. else if (blockStarted && (c == ' ') && (qspGetStatCode(block) == (int)QspStatementType.Close) &&
  637. (line.Length > pos + 3) && line.Substring(pos + 1, 3).Equals("ALL", StringComparison.OrdinalIgnoreCase))
  638. {
  639. //CLOSE ALL
  640. block += c;
  641. }
  642. else if (!comparer && !blockStarted && (c == '*'))
  643. {
  644. //Возможно, *PL, *P, *NL
  645. blockStarted = true;
  646. blockCompleted = false;
  647. block += c;
  648. blockStartPos = pos;
  649. }
  650. else if (!blockStarted && (c == '['))
  651. {
  652. //Квадратная скобка должна идти вплотную к имени массива
  653. SubmitError("A square bracket has to be placed just behind the name of the array, with no spaces", lineNum);
  654. return false;
  655. }
  656. else
  657. {
  658. //Самостоятельные знаки
  659. if (c == '(')
  660. {
  661. bracketLevel++;
  662. }
  663. else if (c == ')')
  664. {
  665. if (bracketLevel == 0)
  666. {
  667. SubmitError("Redundant bracket \")\"", lineNum);
  668. return false;
  669. }
  670. bracketLevel--;
  671. }
  672. bool whiteSpace = c.ToString().IndexOfAny(WhiteSpace) == 0;
  673. if (comparer)
  674. {
  675. //<= >= => =< <> += -=
  676. if (blockStarted)
  677. {
  678. appendDelimiter = true;
  679. delimiterToAppend = cmp;
  680. }
  681. else
  682. {
  683. blockStarted = true;
  684. blockStartPos = pos;
  685. block = cmp;
  686. }
  687. blockCompleted = true;
  688. pos++;
  689. }
  690. else if (blockStarted)
  691. {
  692. blockCompleted = true;
  693. if (!whiteSpace)
  694. {
  695. appendDelimiter = true;
  696. delimiterToAppend += c;
  697. }
  698. else
  699. {
  700. //Обрабатываем END IF, END ACT
  701. int blockCode = qspGetStatCode(block);
  702. if (blockCode == (int)QspStatementType.End)
  703. {
  704. int nextPos = line.LastIndexOfAny(WhiteSpace, blockStartPos + block.Length) + 1;
  705. if (nextPos < line.Length)
  706. {
  707. int delimPos = line.IndexOfAny(Delimiters, nextPos);
  708. string nextWord = "";
  709. if (delimPos == INVALID_INDEX)
  710. nextWord = line.Substring(nextPos);
  711. else
  712. nextWord = line.Substring(nextPos, delimPos - nextPos);
  713. int nextCode = qspGetStatCode(nextWord);
  714. if ((nextCode == (int)QspStatementType.If) || (nextCode == (int)QspStatementType.Act))
  715. {
  716. pos = nextPos + nextWord.Length - 1;
  717. }
  718. }
  719. }
  720. }
  721. }
  722. else if (!whiteSpace)
  723. {
  724. blockStarted = true;
  725. blockCompleted = true;
  726. blockStartPos = pos;
  727. block += c;
  728. }
  729. }
  730. }
  731. else
  732. {
  733. //Просто буквы
  734. if (!blockStarted)
  735. {
  736. blockStarted = true;
  737. blockCompleted = false;
  738. blockStartPos = pos;
  739. }
  740. block += c;
  741. }
  742. }
  743. //Последний символ в строке
  744. if (blockStarted && (pos == line.Length - 1))
  745. {
  746. blockCompleted = true;
  747. }
  748. if (blockCompleted || quotedTextCompleted)
  749. {
  750. if (!quotedTextCompleted && (block.Length == 0))
  751. {
  752. SubmitError("Internal error of analyzer! Empty block!", lineNum);
  753. return false;
  754. }
  755. debugText += "[" + block + "] ";
  756. bool skip = false;
  757. int blockCode = qspGetStatCode(block);
  758. if (blockCode == (int)QspStatementType.If)
  759. {
  760. controlBlock = (int)ControlBlockType.IfCondition;
  761. debugText += "<IfCondition> ";
  762. lastIfPos = blockStartPos;
  763. }
  764. if (blockCode == (int)QspStatementType.Act)
  765. {
  766. controlBlock = (int)ControlBlockType.ActCondition;
  767. debugText += "<ActCondition> ";
  768. lastActPos = blockStartPos;
  769. }
  770. if (blockCode == (int)QspStatementType.ElseIf)
  771. {
  772. if (controlBlock == (int)ControlBlockType.ML_If)
  773. {
  774. controlBlock = (int)ControlBlockType.ElseIfCondition;
  775. debugText += "<ElseIfCondition> ";
  776. lastIfPos = blockStartPos;
  777. }
  778. else
  779. {
  780. SubmitError("ELSEIF без IF", lineNum);
  781. return false;
  782. }
  783. }
  784. if (blockCode == (int)QspStatementType.Else)
  785. {
  786. if (controlBlock == (int)ControlBlockType.ML_If)
  787. {
  788. if (firstSymbolPos == blockStartPos)
  789. {
  790. if ((blockStartPos + block.Length == line.Length) || (line.Substring(blockStartPos + block.Length).Trim(WhiteSpace).Equals(":")))
  791. {
  792. controlBlock = (int)ControlBlockType.ML_Else;
  793. ControlStack.Pop();
  794. ControlLine cline;
  795. cline.controlBlock = ControlBlockType.ML_Else;
  796. cline.line = lineNum;
  797. ControlStack.Push(cline);
  798. }
  799. else
  800. {
  801. SubmitError("An operator cannot be placed after multiline ELSE", lineNum);
  802. return false;
  803. }
  804. }
  805. else
  806. {
  807. SubmitError("Multiline ELSE should be at the beginning of the line", lineNum);
  808. return false;
  809. }
  810. }
  811. else
  812. {
  813. if (controlBlock == (int)ControlBlockType.SL_Act)
  814. {
  815. if (groupInnerCounter > 0)
  816. {
  817. if ((ControlStack.Peek().controlBlock == ControlBlockType.SL_If) && (ControlStack.Peek().line == lineNum))
  818. {
  819. if (blockGroupStarted)
  820. {
  821. blockGroupCompleted = true;
  822. }
  823. }
  824. else
  825. {
  826. SubmitError("ELSE without IF", lineNum);
  827. return false;
  828. }
  829. }
  830. else
  831. {
  832. SubmitError("Invalid notation of single line ACT", lineNum);
  833. return false;
  834. }
  835. }
  836. else if (controlBlock == (int)ControlBlockType.SL_If)
  837. {
  838. if (blockGroupStarted)
  839. {
  840. blockGroupCompleted = true;
  841. }
  842. else if (groupInnerCounter == 0)
  843. {
  844. SubmitError("After single line IF has to be any operators before ELSE", lineNum);
  845. return false;
  846. }
  847. }
  848. else
  849. {
  850. SubmitError("ELSE without IF", lineNum);
  851. return false;
  852. }
  853. //Это правильный ELSE
  854. if (blockStartPos + block.Length < line.Length)
  855. {
  856. string restLine = line.Substring(blockStartPos + block.Length);
  857. if (restLine.Trim(WhiteSpace).StartsWith(":"))
  858. {
  859. pos += restLine.IndexOf(':') + 1;
  860. }
  861. }
  862. ControlStack.Pop();
  863. controlBlock = (int)ControlBlockType.SL_Else;
  864. groupInnerCounter = 0;
  865. }
  866. skip = true;
  867. }
  868. if (blockCode == (int)QspStatementType.End)
  869. {
  870. if (ControlStack.Count > 0)
  871. {
  872. ControlStack.Pop();
  873. if (ControlStack.Count > 0)
  874. {
  875. ControlLine cline = ControlStack.Peek();
  876. controlBlock = (int)cline.controlBlock;
  877. }
  878. else
  879. {
  880. controlBlock = (int)ControlBlockType.None;
  881. }
  882. }
  883. else
  884. {
  885. SubmitError("Redundant END", lineNum);
  886. return false;
  887. }
  888. skip = true;
  889. }
  890. if (!skip)
  891. {
  892. if (!blockGroupStarted)
  893. {
  894. blockGroupStarted = true;
  895. groupInnerCounter++;
  896. if (singleBlockGroup)
  897. {
  898. singleBlockGroup = false;
  899. blockGroupCompleted = true;
  900. }
  901. }
  902. if (quotedTextCompleted)
  903. {
  904. blockGroup.Add(quotedText);
  905. blockInGroupIsText.Add(true);
  906. quotedTextCompleted = false;
  907. }
  908. else
  909. {
  910. if ((blockCode == (int)QspStatementType.Unknown) && (block.Length > 1))
  911. {
  912. //Обрабатываем попытки "склеить" некоторые последовательности символов
  913. string first = block.Substring(0, 1);
  914. string second = block.Substring(1, 1);
  915. if (!second.Equals("=") && first.Equals("*"))
  916. {
  917. //Если была неудачная попытка прочесть *NL, *P, и т.д., "разделяем" блок на части
  918. blockGroup.Add(first);
  919. blockInGroupIsText.Add(false);
  920. block = block.Substring(1);
  921. }
  922. }
  923. blockGroup.Add(block);
  924. blockInGroupIsText.Add(false);
  925. }
  926. if (appendDelimiter)
  927. {
  928. blockGroup.Add(delimiterToAppend);
  929. blockInGroupIsText.Add(false);
  930. }
  931. if (blockGroupStarted && (pos == line.Length - 1))
  932. {
  933. blockGroupCompleted = true;
  934. }
  935. }
  936. block = "";
  937. blockCompleted = false;
  938. blockStarted = false;
  939. }
  940. if (blockGroupCompleted)
  941. {
  942. //Разбор аргументов
  943. if (blockGroup.Count == 0)
  944. {
  945. SubmitError("Internal error of the analyzer! Empty block!", lineNum);
  946. return false;
  947. }
  948. if (!CheckBlockGroup(blockGroup, blockInGroupIsText))
  949. return false;
  950. blockGroup.Clear();
  951. blockInGroupIsText.Clear();
  952. blockGroupStarted = false;
  953. blockGroupCompleted = false;
  954. }
  955. pos++;
  956. }
  957. //Строка закончилась
  958. if (bracketLevel>0)
  959. {
  960. SubmitError("Redundant bracket \"(\"", lineNum);
  961. return false;
  962. }
  963. if (controlBlock == (int)ControlBlockType.IfCondition)
  964. {
  965. SubmitError("IF without \":\"", lineNum);
  966. return false;
  967. }
  968. if (controlBlock == (int)ControlBlockType.ActCondition)
  969. {
  970. SubmitError("ACT without \":\"", lineNum);
  971. return false;
  972. }
  973. if ((controlBlock == (int)ControlBlockType.SL_Act) || (controlBlock == (int)ControlBlockType.SL_If) || (controlBlock == (int)ControlBlockType.SL_Else))
  974. {
  975. if (groupInnerCounter > 0)
  976. {
  977. while ((ControlStack.Count > 0) && (ControlStack.Peek().controlBlock == ControlBlockType.SL_If))
  978. ControlStack.Pop();
  979. if (ControlStack.Count > 0)
  980. {
  981. ControlLine cline = ControlStack.Peek();
  982. controlBlock = (int)cline.controlBlock;
  983. }
  984. else
  985. {
  986. controlBlock = (int)ControlBlockType.None;
  987. }
  988. }
  989. else if (controlBlock == (int)ControlBlockType.SL_Act)
  990. {
  991. SubmitError("Invalid notation of single line ACT", lineNum);
  992. return false;
  993. }
  994. else if (controlBlock == (int)ControlBlockType.SL_If)
  995. {
  996. SubmitError("Invalid notation of single line IF", lineNum);
  997. return false;
  998. }
  999. else if (controlBlock == (int)ControlBlockType.SL_Else)
  1000. {
  1001. SubmitError("In single line IF has to be any operators after ELSE", lineNum);
  1002. return false;
  1003. }
  1004. }
  1005. //для отладки
  1006. if (line.Length > 0)
  1007. {
  1008. debugText += Environment.NewLine;
  1009. }
  1010. if (currentRoot)
  1011. {
  1012. //Вычисляем уровень вложенности(для утилиты форматирования кода)
  1013. int stackSize = ControlStack.Count;
  1014. int level = 0;
  1015. if (stackSize > 0)
  1016. {
  1017. endIndentLevel = stackSize;
  1018. ControlLine cline = ControlStack.Peek();
  1019. int b = (int)cline.controlBlock;
  1020. bool openingLine = cline.line == currentLine;
  1021. if (openingLine && ((b == (int)ControlBlockType.ML_Act) || (b == (int)ControlBlockType.ML_If)))
  1022. {
  1023. level = startIndentLevel;
  1024. }
  1025. else if (openingLine && (b == (int)ControlBlockType.ML_Else))
  1026. {
  1027. level = startIndentLevel - 1;
  1028. }
  1029. else
  1030. {
  1031. level = endIndentLevel;
  1032. }
  1033. }
  1034. location_codeline_level.Add(currentLine, level);
  1035. }
  1036. }
  1037. //Проверка на незакрытые в конце локации многострочные IF и ACT
  1038. if (ControlStack.Count > 0)
  1039. {
  1040. ControlLine cline = ControlStack.Pop();
  1041. if ((cline.controlBlock == ControlBlockType.ML_If) || (cline.controlBlock == ControlBlockType.ML_Else))
  1042. {
  1043. SubmitError("Multi line IF without END", cline.line);
  1044. return false;
  1045. }
  1046. else
  1047. {
  1048. SubmitError("Multi line ACT without END", cline.line);
  1049. return false;
  1050. }
  1051. }
  1052. AddLocationLink(m_name, true, m_start);
  1053. return true;
  1054. }
  1055. bool CheckBlockGroup(List<string> blockGroup, List<bool> blockInGroupIsText)
  1056. {
  1057. //Разбор аргументов для операторов ACT, IF, прочих операторов и функций.
  1058. string pomvarstr1;
  1059. string pomvarstr2;
  1060. bool iifpresent;
  1061. int blockCode = qspGetStatCode(blockGroup.ToArray()[0]);
  1062. if (blockInGroupIsText[0])
  1063. blockCode = (int)QspStatementType.Unknown;
  1064. bool isSetOp = blockCode == (int)QspStatementType.Set;
  1065. if ((blockCode == (int)QspStatementType.Unknown) || isSetOp)
  1066. {
  1067. //Это присваивание?
  1068. int setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "=");
  1069. if (setpos == INVALID_INDEX)
  1070. setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "+=");
  1071. if (setpos == INVALID_INDEX)
  1072. setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "*=");
  1073. if (setpos == INVALID_INDEX)
  1074. setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "/=");
  1075. if (setpos == INVALID_INDEX)
  1076. setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "-=");
  1077. if (isSetOp && (setpos == INVALID_INDEX))
  1078. {
  1079. SubmitError("Not found the char \"=\"", currentLine);
  1080. return false;
  1081. }
  1082. if (setpos != INVALID_INDEX)
  1083. {
  1084. //Присваивание
  1085. if ((setpos == 0) || (isSetOp && (setpos == 1)))
  1086. {
  1087. SubmitError("The name of a variable before the character \"=\" is not specified!", currentLine);
  1088. return false;
  1089. }
  1090. int last = blockGroup.Count - 1;
  1091. if (setpos==last)
  1092. {
  1093. SubmitError("It should be a value after char \"=\"", currentLine);
  1094. return false;
  1095. }
  1096. //Проверяем левую часть
  1097. int start = 0;
  1098. if (isSetOp)
  1099. start = 1;
  1100. int count = setpos - start;
  1101. List<string> args = new List<string>();
  1102. List<bool> types = new List<bool>();
  1103. args = blockGroup.GetRange(start, count);
  1104. types = blockInGroupIsText.GetRange(start, count);
  1105. if (!CheckLeftAssign(args, types))
  1106. return false;
  1107. string assignedVarName = args[0];
  1108. //Проверяем правую часть
  1109. start = setpos + 1;
  1110. count = last - start + 1;
  1111. args = blockGroup.GetRange(start, count);
  1112. types = blockInGroupIsText.GetRange(start, count);
  1113. if (!CheckExpression(args, types))
  1114. return false;
  1115. //Засчитываем присваивание некоторым переменным как обращение к локации
  1116. if ((count == 1) && types[0] && ListContainsIgnoreCase(callerVariables, assignedVarName))
  1117. {
  1118. AddLocationLink(args[0], false, true);
  1119. }
  1120. }
  1121. else
  1122. {
  1123. //Если оператор неизвестен, пытаемся разобрать выражение
  1124. if (!CheckExpression(blockGroup, blockInGroupIsText))
  1125. return false;
  1126. //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
  1127. if ((blockGroup.Count >= 1) && (blockInGroupIsText[0]))
  1128. {
  1129. pomvarstr1 = "";
  1130. pomvarstr2 = "";
  1131. iifpresent = false;
  1132. for (int ibc = 0; ibc < blockGroup.Count; ibc++)
  1133. {
  1134. if (blockGroup[Math.Min(ibc + 1, blockGroup.Count-1)] != "iif")
  1135. {
  1136. pomvarstr1 = pomvarstr1 + blockGroup[ibc];
  1137. pomvarstr2 = pomvarstr2 + blockGroup[ibc];
  1138. }
  1139. else
  1140. {
  1141. iifpresent = true;
  1142. while (blockGroup[ibc] != ",")
  1143. {
  1144. ibc++;
  1145. }
  1146. ibc++;
  1147. pomvarstr1 = pomvarstr1 + blockGroup[ibc];
  1148. ibc++;
  1149. ibc++;
  1150. pomvarstr2 = pomvarstr2 + blockGroup[ibc];
  1151. ibc++;
  1152. ibc++;
  1153. }
  1154. }
  1155. ParseExecInOutputText(pomvarstr1);
  1156. if (iifpresent)
  1157. ParseExecInOutputText(pomvarstr2);
  1158. }
  1159. }
  1160. }
  1161. else if ((blockCode == (int)QspStatementType.If) || (blockCode == (int)QspStatementType.ElseIf))
  1162. {
  1163. int start = 1;
  1164. int count = blockGroup.Count - 1;
  1165. if (count > 0)
  1166. {
  1167. List<string> args = blockGroup.GetRange(start, count);
  1168. List<bool> types = blockInGroupIsText.GetRange(start, count);
  1169. if (!CheckExpression(args, types))
  1170. return false;
  1171. }
  1172. else
  1173. {
  1174. if (blockCode == (int)QspStatementType.If)
  1175. {
  1176. SubmitError("Operator IF without condition", currentLine);
  1177. }
  1178. else
  1179. {
  1180. SubmitError("Operator ELSEIF without condition", currentLine);
  1181. }
  1182. return false;
  1183. }
  1184. }
  1185. else
  1186. {
  1187. //Если оператор известен, проверяем его аргументы.
  1188. int count = blockGroup.Count - 1;
  1189. List<string> args = new List<string>();
  1190. List<bool> types = new List<bool>();
  1191. if (count > 0)
  1192. {
  1193. args = blockGroup.GetRange(1, count);
  1194. types = blockInGroupIsText.GetRange(1, count);
  1195. }
  1196. if (!CheckStatementArgs(blockCode, args, types))
  1197. return false;
  1198. }
  1199. //Проверяем подвыражения вида <<$var>> в любых строках
  1200. for (int i = 0; i < blockGroup.Count; i++)
  1201. {
  1202. if (blockInGroupIsText[i])
  1203. {
  1204. if (!ParseSubExpressions(blockGroup[i]))
  1205. return false;
  1206. }
  1207. }
  1208. return true;
  1209. }
  1210. bool CheckStatementArgs(int code, List<string> argsSrc, List<bool> typesSrc)
  1211. {
  1212. int count = argsSrc.Count;
  1213. List<string> args = new List<string>();
  1214. List<bool> types = new List<bool>();
  1215. if (count > 0)
  1216. {
  1217. if ((count > 1) && argsSrc.ToArray()[0].Equals("(") && !typesSrc.ToArray()[0] &&
  1218. argsSrc.ToArray()[count - 1].Equals(")") && !typesSrc.ToArray()[count - 1])
  1219. {
  1220. //Игнорируем одну пару скобок по краям
  1221. args = argsSrc.GetRange(1, count - 2);
  1222. types = typesSrc.GetRange(1, count - 2);
  1223. }
  1224. else
  1225. {
  1226. args = argsSrc.GetRange(0, count);
  1227. types = typesSrc.GetRange(0, count);
  1228. }
  1229. }
  1230. count = args.Count;
  1231. if ((count >= 1) && types[0])
  1232. {
  1233. //Отмечаем в списке явные ссылки на локации
  1234. if ((code == (int)QspStatementType.GoSub) || (code == (int)QspStatementType.GoTo) ||
  1235. (code == (int)QspStatementType.XGoTo))
  1236. {
  1237. AddLocationLink(args[0], false, true);
  1238. }
  1239. //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
  1240. else if ((code == (int)QspStatementType.P) || (code == (int)QspStatementType.PL) ||
  1241. (code == (int)QspStatementType.NL) || (code == (int)QspStatementType.MP) ||
  1242. (code == (int)QspStatementType.MPL) || (code == (int)QspStatementType.MNL))
  1243. {
  1244. ParseExecInOutputText(args[0]);
  1245. }
  1246. //Отмечаем в списке добавленные предметы
  1247. else if (code == (int)QspStatementType.AddObj)
  1248. {
  1249. AddObj(args[0], true, false);
  1250. }
  1251. //Отмечаем в списке удаленные предметы
  1252. else if (code == (int)QspStatementType.DelObj)
  1253. {
  1254. AddObj(args[0], false, true);
  1255. }
  1256. //Отмечаем в списке добавленные действия
  1257. else if (code == (int)QspStatementType.Act)
  1258. {
  1259. AddAct(args[0], true, false);
  1260. }
  1261. //Отмечаем в списке удаленные действия
  1262. else if (code == (int)QspStatementType.DelAct)
  1263. {
  1264. AddAct(args[0], false, true);
  1265. }
  1266. }
  1267. int minArgCount = qspStats[code].MinArgsCount;
  1268. int maxArgCount = qspStats[code].MaxArgsCount;
  1269. int argCount = 0;
  1270. int curIndex = 0;
  1271. List<string> expr = new List<string>();
  1272. if (count > 0)
  1273. {
  1274. while (true)
  1275. {
  1276. if (argCount == maxArgCount)
  1277. {
  1278. SubmitError("Too many arguments for the operator", currentLine);
  1279. return false;
  1280. }
  1281. int index = FindInTopBracketLevel(args, types, ",", curIndex);
  1282. if (index != INVALID_INDEX)
  1283. {
  1284. if (index > curIndex)
  1285. {
  1286. if (!CheckExpression(args.GetRange(curIndex, index - curIndex), types.GetRange(curIndex, index - curIndex)))
  1287. return false;
  1288. }
  1289. else
  1290. {
  1291. SubmitError("Argument can not be empty", currentLine);
  1292. return false;
  1293. }
  1294. }
  1295. else
  1296. {
  1297. if (!CheckExpression(args.GetRange(curIndex, count - curIndex), types.GetRange(curIndex, count - curIndex)))
  1298. return false;
  1299. }
  1300. argCount++;
  1301. if (index == INVALID_INDEX)
  1302. break;
  1303. curIndex = index + 1;
  1304. if (curIndex == count)
  1305. {
  1306. SubmitError("Argument can not be empty", currentLine);
  1307. return false;
  1308. }
  1309. }
  1310. }
  1311. if (argCount < minArgCount)
  1312. {
  1313. SubmitError("The operator requires more arguments", currentLine);
  1314. return false;
  1315. }
  1316. return true;
  1317. }
  1318. bool CheckExpression(List<string> args, List<bool> types)
  1319. {
  1320. //Проверка выражения
  1321. int[] opStack = new int[QSP_STACKSIZE];
  1322. int[] argStack = new int[QSP_STACKSIZE];
  1323. bool waitForOperator = false;
  1324. int opCode, itemsCount = 0, opSp = -1, argSp = -1;
  1325. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Start))
  1326. return false;
  1327. int argIndex = 0;
  1328. while (argIndex <= args.Count)
  1329. {
  1330. String s = "";
  1331. if (argIndex < args.Count)
  1332. s = args[argIndex];
  1333. if (waitForOperator)
  1334. {
  1335. opCode = qspGetFunctionCode(s, false);
  1336. String nextArg = "";
  1337. bool nextArgIsString = false;
  1338. bool hasNextArg = argIndex + 1 < args.Count;
  1339. if (hasNextArg)
  1340. {
  1341. nextArg = args[argIndex + 1];
  1342. nextArgIsString = types[argIndex + 1];
  1343. }
  1344. if (opCode == (int)QspFunctionType.Unknown || opCode >= (int)QspFunctionType.First_Function)
  1345. {
  1346. SubmitError("Unknown action in the expression", currentLine);
  1347. break;
  1348. }
  1349. if (((opCode == (int)QspFunctionType.And) || (opCode == (int)QspFunctionType.Or) || (opCode == (int)QspFunctionType.Mod)) &&
  1350. !(hasNextArg && (nextArgIsString || nextArg.Equals("(") || (nextArg.IndexOfAny(Delimiters) == INVALID_INDEX)))
  1351. )
  1352. {
  1353. SubmitError("Syntax error", currentLine);
  1354. break;
  1355. }
  1356. bool bError = false;
  1357. while (qspOps[opCode].Priority <= qspOps[opStack[opSp]].Priority && qspOps[opStack[opSp]].Priority != 127)
  1358. {
  1359. if (opStack[opSp] >= (int)QspFunctionType.First_Function) ++argStack[argSp];
  1360. if (!qspAppendToCompiled(ref itemsCount))
  1361. {
  1362. bError = true;
  1363. break;
  1364. }
  1365. if (--opSp < 0 || --argSp < 0)
  1366. {
  1367. SubmitError("Syntax error", currentLine);
  1368. bError = true;
  1369. break;
  1370. }
  1371. }
  1372. if (bError)
  1373. break;
  1374. switch (opCode)
  1375. {
  1376. case (int)QspFunctionType.End:
  1377. if (opSp > 0)
  1378. {
  1379. SubmitError("Closing bracket not found", currentLine);
  1380. bError = true;
  1381. break;
  1382. }
  1383. return itemsCount > 0;
  1384. case (int)QspFunctionType.CloseBracket:
  1385. if (opStack[opSp] != (int)QspFunctionType.OpenBracket)
  1386. {
  1387. SubmitError("Opening bracket not found", currentLine);
  1388. bError = true;
  1389. break;
  1390. }
  1391. opCode = opStack[--opSp];
  1392. if (opCode >= (int)QspFunctionType.First_Function)
  1393. {
  1394. if (argStack[argSp] + 1 < qspOps[opCode].MinArgsCount || argStack[argSp] + 1 > qspOps[opCode].MaxArgsCount)
  1395. {
  1396. SubmitError("Invalid number of arguments", currentLine);
  1397. bError = true;
  1398. }
  1399. }
  1400. else
  1401. --argSp;
  1402. break;
  1403. case (int)QspFunctionType.Comma:
  1404. if ((opSp > 0) && opStack[opSp - 1] >= (int)QspFunctionType.First_Function)
  1405. {
  1406. if (++argStack[argSp] > qspOps[opStack[opSp - 1]].MaxArgsCount)
  1407. {
  1408. SubmitError("Invalid number of arguments", currentLine);
  1409. bError = true;
  1410. break;
  1411. }
  1412. }
  1413. else
  1414. {
  1415. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Comma))
  1416. {
  1417. bError = true;
  1418. break;
  1419. }
  1420. }
  1421. waitForOperator = false;
  1422. break;
  1423. default:
  1424. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
  1425. {
  1426. bError = true;
  1427. break;
  1428. }
  1429. waitForOperator = false;
  1430. break;
  1431. }
  1432. if (bError)
  1433. break;
  1434. }
  1435. else
  1436. {
  1437. if ((argIndex < args.Count) && !types[argIndex] && IsNumber(s))
  1438. {
  1439. if (opStack[opSp] == (int)QspFunctionType.Minus)
  1440. {
  1441. --opSp;
  1442. --argSp;
  1443. }
  1444. if (!qspAppendToCompiled(ref itemsCount))
  1445. break;
  1446. waitForOperator = true;
  1447. }
  1448. // 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
  1449. // I do not assure that I did it in a proper place, but it seems that it works.
  1450. else if ((opStack[1] == (int)QspFunctionType.Func) && (argIndex == 2))
  1451. {
  1452. AddLocationLink(s, false, true);
  1453. }
  1454. else if ((opStack[1] == (int)QspFunctionType.Func) && (argIndex == 3) && (s == ","))
  1455. {
  1456. }
  1457. else if ((argIndex < args.Count) && types[argIndex])
  1458. {
  1459. if (!qspAppendToCompiled(ref itemsCount))
  1460. break;
  1461. waitForOperator = true;
  1462. }
  1463. else if (s.Equals("+"))
  1464. {
  1465. }
  1466. else if (s.Equals("-"))
  1467. {
  1468. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Minus))
  1469. break;
  1470. }
  1471. else if (s.Equals("("))
  1472. {
  1473. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.OpenBracket))
  1474. break;
  1475. }
  1476. else if (s.Equals(")"))
  1477. {
  1478. opCode = opStack[opSp];
  1479. if (opCode != (int)QspFunctionType.OpenBracket)
  1480. {
  1481. if (opCode >= (int)QspFunctionType.First_Function)
  1482. SubmitError("Invalid number of arguments", currentLine);
  1483. else
  1484. SubmitError("Syntax error", currentLine);
  1485. break;
  1486. }
  1487. opCode = opStack[--opSp];
  1488. if (opCode < (int)QspFunctionType.First_Function)
  1489. {
  1490. SubmitError("Syntax error", currentLine);
  1491. break;
  1492. }
  1493. if (qspOps[opCode].MinArgsCount > argSp)
  1494. {
  1495. SubmitError("Invalid number of arguments", currentLine);
  1496. break;
  1497. }
  1498. if (!qspAppendToCompiled(ref itemsCount))
  1499. break;
  1500. --opSp;
  1501. --argSp;
  1502. waitForOperator = true;
  1503. }
  1504. else if ((argIndex < args.Count) && s.IndexOfAny(Delimiters) != 0)
  1505. {
  1506. if (s.IndexOfAny(Delimiters) != INVALID_INDEX)
  1507. {
  1508. SubmitError("Internal error of the analyzer: Invalid characters in the variable name", currentLine);
  1509. break;
  1510. }
  1511. opCode = qspGetFunctionCode(s, true);
  1512. if (opCode >= (int)QspFunctionType.First_Function)
  1513. {
  1514. if ((args.Count - argIndex > 1) && (args[argIndex + 1].Equals("(") && !types[argIndex + 1]))
  1515. {
  1516. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
  1517. break;
  1518. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.OpenBracket))
  1519. break;
  1520. argIndex++;
  1521. --argSp;
  1522. }
  1523. else if (qspOps[opCode].MinArgsCount < 2)
  1524. {
  1525. if (qspOps[opCode].MinArgsCount > 0)
  1526. {
  1527. if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
  1528. break;
  1529. }
  1530. else
  1531. {
  1532. if (!qspAppendToCompiled(ref itemsCount))
  1533. break;
  1534. waitForOperator = true;
  1535. }
  1536. }
  1537. else
  1538. {
  1539. SubmitError("Brackets not found", currentLine);
  1540. break;
  1541. }
  1542. }
  1543. else
  1544. {
  1545. int optArgsCount = 0;
  1546. //Проверяем выражение(индекс массива)
  1547. if ((args.Count - argIndex > 1) && (args[argIndex + 1].Equals("[") && !types[argIndex + 1]))
  1548. {
  1549. int optIndex = argIndex + 2;
  1550. int level = 1;
  1551. bool bFound = false;
  1552. while (optIndex < args.Count)
  1553. {
  1554. if (args[optIndex].Equals("[") && !types[optIndex])
  1555. {
  1556. level++;
  1557. }
  1558. else if (args[optIndex].Equals("]") && !types[optIndex])
  1559. {
  1560. level--;
  1561. if (level == 0)
  1562. {
  1563. bFound = true;
  1564. break;
  1565. }
  1566. }
  1567. optIndex++;
  1568. }
  1569. if (level > 0)
  1570. {
  1571. SubmitError("Unclosed parenthesis \"[\"", currentLine);
  1572. break;
  1573. }
  1574. if (bFound)
  1575. optArgsCount = optIndex - argIndex;
  1576. }
  1577. List<string> subArgs = args.GetRange(argIndex, optArgsCount + 1);
  1578. List<bool> subTypes = types.GetRange(argIndex, optArgsCount + 1);
  1579. if (!CheckVariable(subArgs, subTypes, false))
  1580. break;
  1581. argIndex += optArgsCount;
  1582. if (!qspAppendToCompiled(ref itemsCount))
  1583. break;
  1584. waitForOperator = true;
  1585. }
  1586. }
  1587. else
  1588. {
  1589. if (opStack[opSp] >= (int)QspFunctionType.First_Function)
  1590. SubmitError("Invalid number of arguments", currentLine);
  1591. else
  1592. SubmitError("Syntax error", currentLine);
  1593. break;
  1594. }
  1595. }
  1596. argIndex++;
  1597. }
  1598. return false;
  1599. }
  1600. bool CheckVariable(List<string> args, List<bool> types, bool assignment)
  1601. {
  1602. //Проверка имени переменной
  1603. if ((args.Count == 0) || (args[0].Length == 0) || types[0])
  1604. {
  1605. SubmitError("Internal error of the analyzer: empty name of variable!", currentLine);
  1606. return false;
  1607. }
  1608. string name = args[0];
  1609. int code1 = qspGetStatCode(name);
  1610. int code2 = qspGetFunctionCode(name, true);
  1611. if ((code1 != (int)QspStatementType.Unknown) || (code2 != (int)QspFunctionType.Unknown))
  1612. {
  1613. SubmitError("QSP Keyword \"" + name + "\" cannot be used as a variable name", currentLine);
  1614. return false;
  1615. }
  1616. //Проверяем имя переменной на валидность
  1617. //В имени переменной разрешены все символы, кроме DELIMS и цифры в начале имени
  1618. //Перед именем переменной может находиться префикс "$"
  1619. string checkName = name;
  1620. if (checkName.StartsWith("$"))
  1621. checkName = checkName.Substring(1);
  1622. // $ =
  1623. if (checkName.Length == 0)
  1624. {
  1625. SubmitError("Invalid variable name \"" + name + "\"", currentLine);
  1626. return false;
  1627. }
  1628. // 1asd =
  1629. if (checkName.Substring(0, 1).IndexOfAny(Digits) != INVALID_INDEX)
  1630. {
  1631. SubmitError("Variable name \"" + name + "\" cannot start with a digit", currentLine);
  1632. return false;
  1633. }
  1634. // /asd =
  1635. if (checkName.IndexOfAny(Delimiters) != INVALID_INDEX)
  1636. {
  1637. SubmitError("Invalid symbols in the name of the variable \"" + name + "\"", currentLine);
  1638. return false;
  1639. }
  1640. //Проверяем переменную на "смешанные раскладки"
  1641. if ((checkName.IndexOfAny(LatinLetters) != INVALID_INDEX) && (checkName.IndexOfAny(RussianLetters) != INVALID_INDEX))
  1642. {
  1643. SubmitWarning("English and Russian symbols are used simultaneously in the name of varible \"" + name + "\" , possibly a typo", currentLine);
  1644. }
  1645. //Проверяем выражение(индекс массива)
  1646. if (args.Count > 1)
  1647. {
  1648. if (args.Count > 2 && args[1].Equals("[") && !types[1] &&
  1649. args[args.Count - 1].Equals("]") && !types[args.Count - 1])
  1650. {
  1651. int start = 2;
  1652. int count = args.Count - 3;
  1653. if (count > 0)
  1654. {
  1655. List<string> argsCut = args.GetRange(start, count);
  1656. List<bool> typesCut = types.GetRange(start, count);
  1657. if (!CheckExpression(argsCut, typesCut))
  1658. return false;
  1659. }
  1660. }
  1661. else
  1662. {
  1663. SubmitError("Invalid expression", currentLine);
  1664. return false;
  1665. }
  1666. }
  1667. //Сохраняем имя переменной в глобальном списке
  1668. if (!assignment)
  1669. {
  1670. bool usedBySystem = ListContainsIgnoreCase(systemVariables, name);
  1671. AddVar(name, usedBySystem, true);
  1672. }
  1673. return true;
  1674. }
  1675. bool CheckLeftAssign(List<string> args, List<bool> types)
  1676. {
  1677. //Проверка имени переменной(слева от знака "=" в операции присваивания)
  1678. if ((args.Count == 0) || (args[0].Length == 0) || types[0])
  1679. {
  1680. //Текстовая строка
  1681. SubmitError("Name of the variable should be before char \"=\" in the assignment operation", currentLine);
  1682. return false;
  1683. }
  1684. if (!CheckVariable(args, types, true))
  1685. return false;
  1686. //Сохраняем имя переменной в глобальном списке
  1687. bool usedBySystem = ListContainsIgnoreCase(systemVariables, args[0]);
  1688. AddVar(args[0], true, usedBySystem);
  1689. return true;
  1690. }
  1691. int FindInTopBracketLevel(List<string> args, List<bool> types, string what)
  1692. {
  1693. return FindInTopBracketLevel(args, types, what, 0);
  1694. }
  1695. int FindInTopBracketLevel(List<string> args, List<bool> types, string what, int startIndex)
  1696. {
  1697. //Ищем знак "=" или запятую вне скобок
  1698. int bracketLevel = 0;
  1699. for (int i = startIndex; i < args.Count; i++)
  1700. {
  1701. if (types[i])
  1702. continue;
  1703. string block = args[i];
  1704. if (block.Equals("("))
  1705. {
  1706. bracketLevel++;
  1707. }
  1708. else if (block.Equals(")"))
  1709. {
  1710. bracketLevel--;
  1711. }
  1712. else if (block.Equals(what) && (bracketLevel == 0))
  1713. {
  1714. return i;
  1715. }
  1716. }
  1717. return INVALID_INDEX;
  1718. }
  1719. void ParseExecInOutputText(string text)
  1720. {
  1721. //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
  1722. int pos = 0;
  1723. //Строим "карту" подвыражений.
  1724. //Если подвыражения в строке содержат ошибки, то разбирать теги нет смысла.
  1725. List<int> subExpMap = new List<int>();
  1726. if (!ParseSubExpressions(text, ref subExpMap))
  1727. return;
  1728. int subExpSkipped = 0;
  1729. while (pos < text.Length)
  1730. {
  1731. pos = text.IndexOf("<a", pos);
  1732. if (pos == INVALID_INDEX)
  1733. break;
  1734. if (subExpMap.Count / 2 > subExpSkipped)
  1735. {
  1736. int subExpStartPos = subExpMap[subExpSkipped * 2];
  1737. int subExpEndPos = subExpMap[subExpSkipped * 2 + 1];
  1738. if (subExpStartPos == pos)
  1739. {
  1740. //Пропускаем подвыражения вне тегов
  1741. subExpSkipped++;
  1742. pos = subExpEndPos + 1;
  1743. continue;
  1744. }
  1745. }
  1746. //Разбираем содержимое угловых скобок
  1747. //Внутри HTML-тега кавычки экранируются не через дублирование, как в QSP, а через "\",
  1748. //причем экранирование требуется только внутри окавыченной строки.
  1749. List<string> blockGroup = new List<string>();
  1750. List<bool> blockInGroupIsText = new List<bool>();
  1751. int firstBlockPosition = INVALID_INDEX;
  1752. string quotedText = "";
  1753. string block = "";
  1754. bool tagClosed = false;
  1755. bool quotedTextCompleted = false;
  1756. bool blockCompleted = false;
  1757. pos++;
  1758. int startPos = pos;
  1759. if ((pos < text.Length) && (text[pos] == '/'))
  1760. startPos++;
  1761. int tagQuote = (int)QuoteType.None;
  1762. while (!tagClosed && (pos < text.Length))
  1763. {
  1764. if (subExpMap.Count / 2 > subExpSkipped)
  1765. {
  1766. int subExpStartPos = subExpMap[subExpSkipped * 2];
  1767. int subExpEndPos = subExpMap[subExpSkipped * 2 + 1];
  1768. if (subExpStartPos == pos)
  1769. {
  1770. //Пропускаем подвыражения вне тегов
  1771. subExpSkipped++;
  1772. string subExpText = text.Substring(pos, subExpEndPos - pos + 1);
  1773. if (tagQuote == (int)QuoteType.None)
  1774. block += subExpText;
  1775. else
  1776. quotedText += subExpText;
  1777. pos = subExpEndPos + 1;
  1778. continue;
  1779. }
  1780. }
  1781. char c2 = text[pos];
  1782. if (tagQuote != (int)QuoteType.None)
  1783. {
  1784. //Апостроф либо кавычка
  1785. if (((tagQuote == (int)QuoteType.Single) && (c2 == '\'')) ||
  1786. ((tagQuote == (int)QuoteType.Double) && (c2 == '"')))
  1787. {
  1788. if ((pos - 1 > 0) && (text[pos - 1] == '\\'))
  1789. {
  1790. //Экранированный апостроф либо кавычка
  1791. if (!quotedTextCompleted)
  1792. quotedText = quotedText.Substring(0, quotedText.Length - 1) + c2;
  1793. }
  1794. else
  1795. {
  1796. tagQuote = (int)QuoteType.None;
  1797. quotedTextCompleted = true;
  1798. }
  1799. }
  1800. else if (!quotedTextCompleted)
  1801. {
  1802. quotedText += c2;
  1803. }
  1804. }
  1805. else if (c2 == '>')
  1806. {
  1807. tagClosed = true;
  1808. }
  1809. else if ((block.Length == 0) && (c2 == '\''))
  1810. {
  1811. tagQuote = (int)QuoteType.Single;
  1812. if (text[pos + 1] == '\'')
  1813. {
  1814. pos++;
  1815. }
  1816. }
  1817. else if ((block.Length == 0) && (c2 == '"'))
  1818. {
  1819. tagQuote = (int)QuoteType.Double;
  1820. }
  1821. else if (c2.ToString().IndexOfAny(WhiteSpace) == 0)
  1822. {
  1823. if (block.Length > 0)
  1824. {
  1825. blockCompleted = true;
  1826. }
  1827. }
  1828. else if (c2 == '=')
  1829. {
  1830. if (block.Length > 0)
  1831. {
  1832. blockGroup.Add(block);
  1833. blockInGroupIsText.Add(false);
  1834. }
  1835. block = "=";
  1836. blockCompleted = true;
  1837. }
  1838. else
  1839. {
  1840. if (firstBlockPosition == INVALID_INDEX)
  1841. {
  1842. firstBlockPosition = pos - startPos;
  1843. }
  1844. block += c2;
  1845. }
  1846. if (tagClosed)
  1847. {
  1848. if (block.Length > 0)
  1849. blockCompleted = true;
  1850. }
  1851. if (blockCompleted)
  1852. {
  1853. blockGroup.Add(block);
  1854. blockInGroupIsText.Add(false);
  1855. blockCompleted = false;
  1856. block = "";
  1857. }
  1858. if (quotedTextCompleted)
  1859. {
  1860. blockGroup.Add(quotedText);
  1861. blockInGroupIsText.Add(true);
  1862. quotedTextCompleted = false;
  1863. quotedText = "";
  1864. }
  1865. pos++;
  1866. }
  1867. if (tagQuote == (int)QuoteType.Single)
  1868. {
  1869. SubmitWarning("Unclosed apostrophe inside the tag", currentLine);
  1870. break;
  1871. }
  1872. else if (tagQuote == (int)QuoteType.Double)
  1873. {
  1874. SubmitWarning("Unclosed quote inside the tag", currentLine);
  1875. break;
  1876. }
  1877. if (!tagClosed)
  1878. {
  1879. SubmitWarning("Unclosed tag",currentLine);
  1880. break;
  1881. }
  1882. if (firstBlockPosition > 0)
  1883. {
  1884. SubmitWarning("The name of the tag should follow immediately after the opening angle bracket, without spaces", currentLine);
  1885. break;
  1886. }
  1887. //Ищем HREF в атрибутах тега A
  1888. int hrefIndex = INVALID_INDEX;
  1889. if ((blockGroup.Count > 3) && (blockGroup[0].Equals("A", StringComparison.OrdinalIgnoreCase)) && !blockInGroupIsText[0])
  1890. {
  1891. for (int i = 1; i + 2 < blockGroup.Count; i++)
  1892. {
  1893. if (blockGroup[i].Equals("HREF", StringComparison.OrdinalIgnoreCase) && !blockInGroupIsText[i] &&
  1894. blockGroup[i + 1].Equals("=") && !blockInGroupIsText[i + 1])
  1895. {
  1896. hrefIndex = i + 2;
  1897. }
  1898. }
  1899. }
  1900. if (hrefIndex != INVALID_INDEX)
  1901. {
  1902. string hrefText = blockGroup[hrefIndex];
  1903. int execKeywordLength = "EXEC:".Length;
  1904. if (hrefText.StartsWith("EXEC:", StringComparison.OrdinalIgnoreCase) && (hrefText.Length > execKeywordLength))
  1905. {
  1906. string execText = hrefText.Substring(execKeywordLength);
  1907. List<int> subExpMapExec = new List<int>();
  1908. ParseSubExpressions(execText, ref subExpMapExec);
  1909. if (subExpMapExec.Count == 0)
  1910. {
  1911. //В EXEC не разбираем код с подвыражениями, это невозможно без интерпретации
  1912. List<string> tagLines = new List<string>(execText.Split('\n'));
  1913. bool wasRoot = currentRoot;
  1914. currentRoot = false;
  1915. ParseLocation(tagLines, currentRoot);
  1916. currentRoot = wasRoot;
  1917. }
  1918. }
  1919. }
  1920. }
  1921. }
  1922. bool ParseSubExpressions(string text)
  1923. {
  1924. List<int> dummy = null;
  1925. return ParseSubExpressions(text, ref dummy);
  1926. }
  1927. bool ParseSubExpressions(string text, ref List<int> subExpMap)
  1928. {
  1929. bool quiet = subExpMap != null;
  1930. //Разбираем подвыражения - <<$var>>
  1931. if (quiet)
  1932. subExpMap.Clear();
  1933. int pos = 0;
  1934. bool valid = true;
  1935. while (valid && pos < text.Length)
  1936. {
  1937. pos = text.IndexOf("<<", pos);
  1938. if (pos == INVALID_INDEX)
  1939. break;
  1940. if (quiet)
  1941. subExpMap.Add(pos);
  1942. //Разбираем содержимое двойных угловых скобок
  1943. string subText = "";
  1944. bool subClosed = false;
  1945. pos += 2;
  1946. int subQuote = (int)QuoteType.None;
  1947. int curlyLevel = 0;
  1948. while (pos < text.Length)
  1949. {
  1950. char c2 = text[pos];
  1951. if (subQuote == (int)QuoteType.None)
  1952. {
  1953. if ((c2 == '>') && (pos + 1 < text.Length) && (text[pos + 1] == '>') && (curlyLevel == 0))
  1954. {
  1955. subClosed = true;
  1956. break;
  1957. }
  1958. else if (c2 == '\'')
  1959. {
  1960. subQuote = (int)QuoteType.Single;
  1961. }
  1962. else if (c2 == '"')
  1963. {
  1964. subQuote = (int)QuoteType.Double;
  1965. }
  1966. else if (c2 == '{')
  1967. {
  1968. curlyLevel++;
  1969. }
  1970. else if (c2 == '}')
  1971. {
  1972. curlyLevel--;
  1973. }
  1974. }
  1975. else if (((subQuote == (int)QuoteType.Single) && (c2 == '\'')) ||
  1976. ((subQuote == (int)QuoteType.Double) && (c2 == '"')))
  1977. {
  1978. //Апостроф или кавычка
  1979. if ((pos + 1 < text.Length) && (
  1980. ((subQuote == (int)QuoteType.Single) && (text[pos + 1] == '\'')) ||
  1981. ((subQuote == (int)QuoteType.Double) && (text[pos + 1] == '"'))))
  1982. {
  1983. //Экранированный апостроф либо кавычка
  1984. }
  1985. else
  1986. {
  1987. subQuote = (int)QuoteType.None;
  1988. }
  1989. }
  1990. subText += c2;
  1991. pos++;
  1992. }
  1993. if (quiet)
  1994. {
  1995. if (subClosed)
  1996. subExpMap.Add(pos + 1);
  1997. else
  1998. subExpMap.Add(pos - 1);
  1999. }
  2000. if (subQuote == (int)QuoteType.Single)
  2001. {
  2002. if (!quiet)
  2003. SubmitError("Unclosed apostrophe in a subexpression", currentLine);
  2004. valid = false;
  2005. break;
  2006. }
  2007. else if (subQuote == (int)QuoteType.Double)
  2008. {
  2009. if (!quiet)
  2010. SubmitError("Unclosed quote in a subexpression", currentLine);
  2011. valid = false;
  2012. break;
  2013. }
  2014. else if (curlyLevel != 0)
  2015. {
  2016. if (!quiet)
  2017. SubmitError("Unclosed curly bracket in a subexpression", currentLine);
  2018. valid = false;
  2019. break;
  2020. }
  2021. if (!subClosed)
  2022. {
  2023. if (!quiet)
  2024. SubmitError("Unclosed subexpression", currentLine);
  2025. valid = false;
  2026. break;
  2027. }
  2028. if (subText.Trim(WhiteSpace).Length == 0)
  2029. {
  2030. if (!quiet)
  2031. SubmitError("Empty subexpression", currentLine);
  2032. valid = false;
  2033. break;
  2034. }
  2035. if (!quiet)
  2036. {
  2037. //Парсим подвыражение как исполняемый код.
  2038. //Для того, чтобы строка считалась именно выражением, добавляем ''+ в начало
  2039. subText = "''+" + subText;
  2040. List<string> subLines = new List<string>(subText.Split('\n'));
  2041. bool wasRoot = currentRoot;
  2042. currentRoot = false;
  2043. valid = ParseLocation(subLines, currentRoot);
  2044. currentRoot = wasRoot;
  2045. }
  2046. }
  2047. return valid;
  2048. }
  2049. }
  2050. public class QSPGameCode : Common
  2051. {
  2052. Hashtable m_LocationsByName;
  2053. List<Location> m_LocationsByOrder;
  2054. Location m_lastLocation;
  2055. public QSPGameCode()
  2056. {
  2057. m_LocationsByName = new Hashtable();
  2058. m_LocationsByOrder = new List<Location>();
  2059. m_lastLocation = null;
  2060. }
  2061. public bool ParseGame(string fileName, object sender, DoWorkEventArgs e)
  2062. {
  2063. int totalLines = 0;
  2064. StreamReader rTl = new StreamReader(fileName);
  2065. while (rTl.ReadLine() != null) { totalLines++; };
  2066. m_LocationsByName.Clear();
  2067. m_LocationsByOrder.Clear();
  2068. ClearErrors();
  2069. m_lastLocation = null;
  2070. currentLocation = "";
  2071. vars = new List<QspVariable>();
  2072. locationLinks = new List<QspLocationLink>();
  2073. objects = new List<QspObj>();
  2074. acts = new List<QspAct>();
  2075. StreamReader fi = null;
  2076. if (!OpenStreamForReading(ref fi, fileName))
  2077. {
  2078. return false;
  2079. }
  2080. string s;
  2081. int line_counter = 0;
  2082. List<string> locationCode = new List<string>();
  2083. bool inside = false;
  2084. while ((s = fi.ReadLine()) != null)
  2085. {
  2086. line_counter++;
  2087. string trimmed = s.Trim(WhiteSpace);
  2088. if ((trimmed.Length > 0) && (trimmed[0] == '#'))
  2089. {
  2090. //имя локации
  2091. string locName = trimmed.Substring(1).Trim(WhiteSpace);
  2092. if (!AddLocation(locName, line_counter))
  2093. {
  2094. fi.Close();
  2095. rTl.Close();
  2096. return false;
  2097. }
  2098. currentLocation = locName;
  2099. inside = true;
  2100. }
  2101. else if ((trimmed.Length > 38) && trimmed.StartsWith("--- ") && trimmed.EndsWith(" ---------------------------------"))
  2102. {
  2103. inside = false;
  2104. Location lastLoc = GetLastLocation();
  2105. if (lastLoc != null)
  2106. {
  2107. lastLoc.ParseLocation(locationCode, true);
  2108. locationCode.Clear();
  2109. currentLocation = "";
  2110. }
  2111. }
  2112. else
  2113. {
  2114. if (inside && GetLastLocation() != null)
  2115. locationCode.Add(s);
  2116. }
  2117. (sender as BackgroundWorker).ReportProgress(Convert.ToInt32(((double)line_counter/(double)totalLines) * 100));
  2118. if ((sender as BackgroundWorker).CancellationPending)
  2119. {
  2120. e.Cancel = true;
  2121. return true;
  2122. }
  2123. }
  2124. fi.Close();
  2125. rTl.Close();
  2126. return true;
  2127. }
  2128. public bool AddLocation(string name, int line)
  2129. {
  2130. if (name.Length <= 0)
  2131. {
  2132. SubmitError("Empty name of location", line);
  2133. return false;
  2134. }
  2135. if (m_LocationsByName.ContainsKey(name))
  2136. {
  2137. SubmitError("Location named " + name + " exist already", line);
  2138. return false;
  2139. }
  2140. Location newLoc = new Location(this, name, line, m_LocationsByOrder.Count == 0);
  2141. m_LocationsByName.Add(name, newLoc);
  2142. m_LocationsByOrder.Add(newLoc);
  2143. m_lastLocation = newLoc;
  2144. return true;
  2145. }
  2146. public Location GetLastLocation()
  2147. {
  2148. return m_lastLocation;
  2149. }
  2150. public Hashtable GetLocationsByName()
  2151. {
  2152. return m_LocationsByName;
  2153. }
  2154. public Location GetLocation(string locationName)
  2155. {
  2156. Location loc = (Location)m_LocationsByName[locationName];
  2157. return loc;
  2158. }
  2159. public bool Beautify(string fileName)
  2160. {
  2161. //Причесываем код - добавляем пробелов
  2162. StreamWriter fo = null;
  2163. if (!OpenStreamForWriting(ref fo, fileName))
  2164. return false;
  2165. for (int i = 0; i < m_LocationsByOrder.Count; i++)
  2166. {
  2167. Location loc = (Location)m_LocationsByOrder[i];
  2168. fo.WriteLine("# " + loc.GetName());
  2169. for (int j = 0; j < loc.GetCodeLinesCount(); j++)
  2170. {
  2171. string text = "";
  2172. int level = INVALID_INDEX;
  2173. loc.GetCodeLine(j, ref text, ref level);
  2174. if (level != INVALID_INDEX)
  2175. {
  2176. text = new string(' ', level * 4) + text.TrimStart(WhiteSpace);
  2177. }
  2178. fo.WriteLine(text);
  2179. }
  2180. fo.WriteLine("--- " + loc.GetName() + " ---------------------------------");
  2181. fo.WriteLine();
  2182. }
  2183. fo.Close();
  2184. return true;
  2185. }
  2186. }
  2187. }