Common.cs 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5. namespace Analyser
  6. {
  7. public class Common
  8. {
  9. const int QSP_MAXSTATSNAMES = 100;
  10. const int QSP_STATSLEVELS = 3;
  11. const int QSP_STATMAXARGS = 10;
  12. const int QSP_OPSLEVELS = 2;
  13. const int QSP_MAXOPSNAMES = 100;
  14. const int QSP_OPMAXARGS = 10;
  15. public const int QSP_STACKSIZE = 30;
  16. public const int QSP_MAXITEMS = 100;
  17. public const int INVALID_INDEX = -1;
  18. static public char[] WhiteSpace = {' ', '\t', '\r', '\n'};
  19. //Разделители - " \t&'\"()[]=!<>+-/*:,{}"
  20. static public char[] Delimiters = " \t&'\"()[]=!<>+-/*:,{}".ToCharArray();
  21. static public char[] Digits = "0123456789".ToCharArray();
  22. static public char[] LatinLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqsrtuvwxyz".ToCharArray();
  23. static public char[] RussianLetters = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъьэюя".ToCharArray();
  24. public struct QspStatement
  25. {
  26. public int ExtArg;
  27. public int MinArgsCount;
  28. public int MaxArgsCount;
  29. public int[] ArgsTypes;
  30. }
  31. public struct QspStatementName
  32. {
  33. public string Name;
  34. public int NameLen;
  35. public int Code;
  36. }
  37. public enum QspStatementType
  38. {
  39. Unknown,
  40. Label,
  41. Comment,
  42. Act,
  43. For,
  44. Local,
  45. If,
  46. ElseIf,
  47. Else,
  48. End,
  49. AddObj,
  50. ClA,
  51. Clear,
  52. CloseAll,
  53. Close,
  54. ClS,
  55. CmdClear,
  56. CopyArr,
  57. DelAct,
  58. DelObj,
  59. Dynamic,
  60. Exec,
  61. Exit,
  62. FreeLib,
  63. GoSub,
  64. GoTo,
  65. IncLib,
  66. Jump,
  67. KillAll,
  68. KillObj,
  69. KillVar,
  70. MClear,
  71. Menu,
  72. MNL,
  73. MPL,
  74. MP,
  75. Msg,
  76. NL,
  77. OpenGame,
  78. OpenQst,
  79. Play,
  80. PL,
  81. P,
  82. RefInt,
  83. SaveGame,
  84. SetTimer,
  85. Set,
  86. ShowActs,
  87. ShowInput,
  88. ShowObjs,
  89. ShowVars,
  90. UnSelect,
  91. View,
  92. Wait,
  93. XGoTo,
  94. Last_Statement
  95. };
  96. public struct QspFunction
  97. {
  98. public int Priority;
  99. public int ResType;
  100. public int MinArgsCount;
  101. public int MaxArgsCount;
  102. public int[] ArgsTypes;
  103. }
  104. public struct QspFunctionName
  105. {
  106. public string Name;
  107. public int NameLen;
  108. public int Code;
  109. }
  110. public enum QspFunctionType
  111. {
  112. Unknown,
  113. Start,
  114. End,
  115. Value,
  116. OpenBracket,
  117. Minus,
  118. Comma,
  119. CloseBracket,
  120. Mul,
  121. Div,
  122. Add,
  123. Sub,
  124. Mod,
  125. Ne,
  126. Leq,
  127. Geq,
  128. Eq,
  129. Lt,
  130. Gt,
  131. And,
  132. Or,
  133. Append,
  134. First_Function,
  135. Not = First_Function,
  136. Loc,
  137. Obj,
  138. Min,
  139. Max,
  140. Rand,
  141. IIf,
  142. RGB,
  143. Len,
  144. IsNum,
  145. LCase,
  146. UCase,
  147. Input,
  148. Str,
  149. Val,
  150. ArrSize,
  151. IsPlay,
  152. Desc,
  153. Trim,
  154. GetObj,
  155. StrComp,
  156. StrFind,
  157. StrPos,
  158. Mid,
  159. ArrPos,
  160. ArrComp,
  161. Instr,
  162. Replace,
  163. Func,
  164. DynEval,
  165. Rnd,
  166. CountObj,
  167. MsecsCount,
  168. QSPVer,
  169. UserText,
  170. CurLoc,
  171. SelObj,
  172. SelAct,
  173. MainText,
  174. StatText,
  175. CurActs,
  176. Last_Operation
  177. };
  178. static public QspStatement[] qspStats;
  179. static QspStatementName[,] qspStatsNames;
  180. static int[] qspStatsNamesCounts;
  181. static int qspStatMaxLen;
  182. static public QspFunction[] qspOps;
  183. static QspFunctionName[,] qspOpsNames;
  184. static int[] qspOpsNamesCounts;
  185. static int qspOpMaxLen;
  186. static bool inited = false;
  187. public class QspVariable
  188. {
  189. public bool IsString;
  190. public string Name;
  191. public bool Assigned;
  192. public bool Used;
  193. public QspVariable(string name, bool assigned, bool used)
  194. {
  195. IsString = name.IndexOf('$') == 0;
  196. Name = name;
  197. Assigned = assigned;
  198. Used = used;
  199. }
  200. }
  201. public class QspLocationLink
  202. {
  203. public string LocationName;
  204. public bool LocationExists;
  205. public bool LocationCalled;
  206. public QspLocationLink(string name, bool exists, bool called)
  207. {
  208. LocationName = name;
  209. LocationExists = exists;
  210. LocationCalled = called;
  211. }
  212. }
  213. public class QspObj
  214. {
  215. public string Name;
  216. public bool Added;
  217. public bool Removed;
  218. public QspObj(string name, bool added, bool removed)
  219. {
  220. Name = name;
  221. Added = added;
  222. Removed = removed;
  223. }
  224. }
  225. public class QspAct
  226. {
  227. public string Name;
  228. public bool Added;
  229. public bool Removed;
  230. public QspAct(string name, bool added, bool removed)
  231. {
  232. Name = name;
  233. Added = added;
  234. Removed = removed;
  235. }
  236. }
  237. static public List<QspVariable> vars;
  238. static public List<QspLocationLink> locationLinks;
  239. static public List<QspObj> objects;
  240. static public List<QspAct> acts;
  241. static public List<string> callerVariables;
  242. static public List<string> systemVariables;
  243. static public bool curlyParsing;
  244. static public string currentLocation;
  245. public enum QuoteType
  246. {
  247. None,
  248. Single,
  249. Double
  250. }
  251. public struct QspError
  252. {
  253. public string locationName; //Локация, на которой встретилась ошибка
  254. public string text; //Текст сообщения об ошибке
  255. public int line; //Номер строки в локации
  256. public bool isError; //Тип ошибки, если "true" - ошибка синтаксиса, если "false" - предупреждение
  257. }
  258. static List<QspError> m_errors;
  259. static int m_errorCounter;
  260. public static int GetErrorsCount()
  261. {
  262. return m_errorCounter;
  263. }
  264. static int m_warningCounter;
  265. public static int GetWarningsCount()
  266. {
  267. return m_warningCounter;
  268. }
  269. public Common()
  270. {
  271. if (!inited)
  272. {
  273. inited = true;
  274. qspStats = new QspStatement[(int)QspStatementType.Last_Statement];
  275. qspStatsNames = new QspStatementName[QSP_STATSLEVELS, QSP_MAXSTATSNAMES];
  276. qspStatsNamesCounts = new int[QSP_STATSLEVELS];
  277. qspOps = new QspFunction[(int)QspFunctionType.Last_Operation];
  278. qspOpsNames = new QspFunctionName[QSP_OPSLEVELS, QSP_MAXOPSNAMES];
  279. qspOpsNamesCounts = new int[QSP_OPSLEVELS];
  280. m_errors = new List<QspError>();
  281. InitQsp();
  282. ClearErrors();
  283. }
  284. }
  285. static public void ClearErrors()
  286. {
  287. m_errors.Clear();
  288. m_errorCounter = 0;
  289. m_warningCounter = 0;
  290. }
  291. static public void ClearNonGameErrors()
  292. {
  293. for (int index = 0; index < m_errors.Count; ++index)
  294. {
  295. if (m_errors[index].isError && (m_errors[index].line == INVALID_INDEX))
  296. {
  297. m_errors.RemoveAt(index);
  298. --index;
  299. m_errorCounter--;
  300. }
  301. }
  302. }
  303. static public void SubmitError(string text, int line)
  304. {
  305. QspError e;
  306. e.locationName = currentLocation;
  307. e.text = text;
  308. e.line = line;
  309. e.isError = true;
  310. m_errors.Add(e);
  311. m_errorCounter++;
  312. }
  313. static public void SubmitWarning(string text, int line)
  314. {
  315. QspError w;
  316. w.locationName = currentLocation;
  317. w.text = text;
  318. w.line = line;
  319. w.isError = false;
  320. m_errors.Add(w);
  321. m_warningCounter++;
  322. }
  323. static public List<QspError> GetErrors()
  324. {
  325. return m_errors;
  326. }
  327. static public bool StartOfMultiWordOperator(string op)
  328. {
  329. return op.ToUpper().Equals("ADD") || op.ToUpper().Equals("DEL");
  330. }
  331. static public void qspAddStatement(int statCode, int extArg, /*QSP_STATEMENT func,*/ int minArgs, int maxArgs, params int[] marker)
  332. {
  333. int i;
  334. qspStats[statCode].ExtArg = extArg;
  335. //qspStats[statCode].Func = func;
  336. qspStats[statCode].MinArgsCount = minArgs;
  337. qspStats[statCode].MaxArgsCount = maxArgs;
  338. qspStats[statCode].ArgsTypes = new int[QSP_STATMAXARGS];
  339. if (maxArgs > 0)
  340. {
  341. for (i = 0; i < maxArgs; ++i)
  342. qspStats[statCode].ArgsTypes[i] = marker[i];
  343. }
  344. }
  345. static public void qspAddStatName(int statCode, string statName, int level)
  346. {
  347. int len = statName.Length;
  348. int count = qspStatsNamesCounts[level];
  349. qspStatsNames[level, count].Name = statName;
  350. qspStatsNames[level, count].NameLen = len;
  351. qspStatsNames[level, count].Code = statCode;
  352. qspStatsNamesCounts[level] = count + 1;
  353. /* Max length */
  354. if (len > qspStatMaxLen) qspStatMaxLen = len;
  355. }
  356. static public void qspAddOperation(int opCode, int priority, /*QSP_FUNCTION func,*/ int resType, int minArgs, int maxArgs, params int[] marker)
  357. {
  358. int i;
  359. qspOps[opCode].Priority = priority;
  360. //qspOps[opCode].Func = func;
  361. qspOps[opCode].ResType = resType;
  362. qspOps[opCode].MinArgsCount = minArgs;
  363. qspOps[opCode].MaxArgsCount = maxArgs;
  364. qspOps[opCode].ArgsTypes = new int[QSP_OPMAXARGS];
  365. if (maxArgs > 0)
  366. {
  367. for (i = 0; i < maxArgs; ++i)
  368. qspOps[opCode].ArgsTypes[i] = marker[i];
  369. }
  370. }
  371. static public void qspAddOpName(int opCode, string opName, int level)
  372. {
  373. int len = opName.Length;
  374. int count = qspOpsNamesCounts[level];
  375. qspOpsNames[level, count].Name = opName;
  376. qspOpsNames[level, count].NameLen = len;
  377. qspOpsNames[level, count].Code = opCode;
  378. qspOpsNamesCounts[level] = count + 1;
  379. /* Max length */
  380. if (len > qspOpMaxLen) qspOpMaxLen = len;
  381. }
  382. static public void InitQsp()
  383. {
  384. qspStatMaxLen = 0;
  385. // код оператора, ExtArg, минимальное кол-во аргументов, максимальное кол-во аргументов, типы аргументов
  386. // 0 - авто
  387. // 1 - строка
  388. // 2 - числовой
  389. qspAddStatement((int)QspStatementType.Else, 0, 0, 0);
  390. qspAddStatement((int)QspStatementType.ElseIf, 0, 1, 1, 2);
  391. qspAddStatement((int)QspStatementType.End, 0, 0, 0);
  392. qspAddStatement((int)QspStatementType.Local, 0, 0, 0);
  393. qspAddStatement((int)QspStatementType.Set, 0, 0, 0);
  394. qspAddStatement((int)QspStatementType.If, 0, 1, 1, 2);
  395. qspAddStatement((int)QspStatementType.Act, 0, 1, 2, 1, 1);
  396. qspAddStatement((int)QspStatementType.For, 0, 0, 0);
  397. qspAddStatement((int)QspStatementType.AddObj, 0, 1, 3, 1, 1, 2);
  398. qspAddStatement((int)QspStatementType.ClA, 3, 0, 0);
  399. qspAddStatement((int)QspStatementType.CloseAll, 1, 0, 0);
  400. qspAddStatement((int)QspStatementType.Close, 0, 0, 1, 1);
  401. qspAddStatement((int)QspStatementType.ClS, 4, 0, 0);
  402. qspAddStatement((int)QspStatementType.CmdClear, 2, 0, 0);
  403. qspAddStatement((int)QspStatementType.CopyArr, 0, 2, 4, 1, 1, 2, 2);
  404. qspAddStatement((int)QspStatementType.DelAct, 0, 1, 1, 1);
  405. qspAddStatement((int)QspStatementType.DelObj, 0, 1, 1, 1);
  406. qspAddStatement((int)QspStatementType.Dynamic, 0, 1, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  407. qspAddStatement((int)QspStatementType.Exec, 0, 1, 1, 1);
  408. qspAddStatement((int)QspStatementType.Exit, 0, 0, 0);
  409. qspAddStatement((int)QspStatementType.FreeLib, 6, 0, 0);
  410. qspAddStatement((int)QspStatementType.GoSub, 0, 1, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  411. qspAddStatement((int)QspStatementType.GoTo, 1, 1, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  412. qspAddStatement((int)QspStatementType.IncLib, 1, 1, 1, 1);
  413. qspAddStatement((int)QspStatementType.Jump, 0, 1, 1, 1);
  414. qspAddStatement((int)QspStatementType.KillAll, 5, 0, 0);
  415. qspAddStatement((int)QspStatementType.KillObj, 1, 0, 1, 2);
  416. qspAddStatement((int)QspStatementType.KillVar, 0, 0, 2, 1, 2);
  417. qspAddStatement((int)QspStatementType.Menu, 0, 1, 3, 1, 2, 2);
  418. qspAddStatement((int)QspStatementType.MClear, 1, 0, 0);
  419. qspAddStatement((int)QspStatementType.MNL, 5, 0, 1, 1);
  420. qspAddStatement((int)QspStatementType.MPL, 3, 0, 1, 1);
  421. qspAddStatement((int)QspStatementType.MP, 1, 1, 1, 1);
  422. qspAddStatement((int)QspStatementType.Clear, 0, 0, 0);
  423. qspAddStatement((int)QspStatementType.NL, 4, 0, 1, 1);
  424. qspAddStatement((int)QspStatementType.PL, 2, 0, 1, 1);
  425. qspAddStatement((int)QspStatementType.P, 0, 1, 1, 1);
  426. qspAddStatement((int)QspStatementType.Msg, 0, 1, 1, 1);
  427. qspAddStatement((int)QspStatementType.OpenGame, 0, 0, 1, 1);
  428. qspAddStatement((int)QspStatementType.OpenQst, 0, 1, 1, 1);
  429. qspAddStatement((int)QspStatementType.Play, 0, 1, 2, 1, 2);
  430. qspAddStatement((int)QspStatementType.RefInt, 0, 0, 0);
  431. qspAddStatement((int)QspStatementType.SaveGame, 0, 0, 1, 1);
  432. qspAddStatement((int)QspStatementType.SetTimer, 0, 1, 1, 2);
  433. qspAddStatement((int)QspStatementType.ShowActs, 0, 1, 1, 2);
  434. qspAddStatement((int)QspStatementType.ShowInput, 3, 1, 1, 2);
  435. qspAddStatement((int)QspStatementType.ShowObjs, 1, 1, 1, 2);
  436. qspAddStatement((int)QspStatementType.ShowVars, 2, 1, 1, 2);
  437. qspAddStatement((int)QspStatementType.UnSelect, 0, 0, 0);
  438. qspAddStatement((int)QspStatementType.View, 0, 0, 1, 1);
  439. qspAddStatement((int)QspStatementType.Wait, 0, 1, 1, 2);
  440. qspAddStatement((int)QspStatementType.XGoTo, 0, 1, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  441. /* Names */
  442. qspAddStatName((int)QspStatementType.Else, "ELSE", 2);
  443. qspAddStatName((int)QspStatementType.ElseIf, "ELSEIF", 1);
  444. qspAddStatName((int)QspStatementType.End, "END", 2);
  445. qspAddStatName((int)QspStatementType.Local, "LOCAL", 2);
  446. qspAddStatName((int)QspStatementType.Set, "SET", 2);
  447. qspAddStatName((int)QspStatementType.Set, "LET", 2);
  448. qspAddStatName((int)QspStatementType.If, "IF", 2);
  449. qspAddStatName((int)QspStatementType.Act, "ACT", 2);
  450. qspAddStatName((int)QspStatementType.For, "FOR", 2);
  451. qspAddStatName((int)QspStatementType.AddObj, "ADDOBJ", 2);
  452. qspAddStatName((int)QspStatementType.AddObj, "ADD OBJ", 2);
  453. qspAddStatName((int)QspStatementType.ClA, "CLA", 2);
  454. qspAddStatName((int)QspStatementType.CloseAll, "CLOSE ALL", 1);
  455. qspAddStatName((int)QspStatementType.Close, "CLOSE", 2);
  456. qspAddStatName((int)QspStatementType.ClS, "CLS", 2);
  457. qspAddStatName((int)QspStatementType.CmdClear, "CMDCLEAR", 2);
  458. qspAddStatName((int)QspStatementType.CmdClear, "CMDCLR", 2);
  459. qspAddStatName((int)QspStatementType.CopyArr, "COPYARR", 2);
  460. qspAddStatName((int)QspStatementType.DelAct, "DELACT", 2);
  461. qspAddStatName((int)QspStatementType.DelAct, "DEL ACT", 2);
  462. qspAddStatName((int)QspStatementType.DelObj, "DELOBJ", 2);
  463. qspAddStatName((int)QspStatementType.DelObj, "DEL OBJ", 2);
  464. qspAddStatName((int)QspStatementType.Dynamic, "DYNAMIC", 2);
  465. qspAddStatName((int)QspStatementType.Exec, "EXEC", 2);
  466. qspAddStatName((int)QspStatementType.Exit, "EXIT", 2);
  467. qspAddStatName((int)QspStatementType.FreeLib, "FREELIB", 2);
  468. qspAddStatName((int)QspStatementType.GoSub, "GOSUB", 2);
  469. qspAddStatName((int)QspStatementType.GoSub, "GS", 2);
  470. qspAddStatName((int)QspStatementType.GoTo, "GOTO", 2);
  471. qspAddStatName((int)QspStatementType.GoTo, "GT", 2);
  472. qspAddStatName((int)QspStatementType.IncLib, "INCLIB", 2);
  473. qspAddStatName((int)QspStatementType.Jump, "JUMP", 2);
  474. qspAddStatName((int)QspStatementType.KillAll, "KILLALL", 2);
  475. qspAddStatName((int)QspStatementType.KillObj, "KILLOBJ", 2);
  476. qspAddStatName((int)QspStatementType.KillVar, "KILLVAR", 2);
  477. qspAddStatName((int)QspStatementType.Menu, "MENU", 2);
  478. qspAddStatName((int)QspStatementType.MClear, "*CLEAR", 2);
  479. qspAddStatName((int)QspStatementType.MClear, "*CLR", 2);
  480. qspAddStatName((int)QspStatementType.MNL, "*NL", 2);
  481. qspAddStatName((int)QspStatementType.MPL, "*PL", 1);
  482. qspAddStatName((int)QspStatementType.MP, "*P", 2);
  483. qspAddStatName((int)QspStatementType.Clear, "CLEAR", 2);
  484. qspAddStatName((int)QspStatementType.Clear, "CLR", 2);
  485. qspAddStatName((int)QspStatementType.NL, "NL", 2);
  486. qspAddStatName((int)QspStatementType.PL, "PL", 1);
  487. qspAddStatName((int)QspStatementType.P, "P", 2);
  488. qspAddStatName((int)QspStatementType.Msg, "MSG", 2);
  489. qspAddStatName((int)QspStatementType.OpenGame, "OPENGAME", 2);
  490. qspAddStatName((int)QspStatementType.OpenQst, "OPENQST", 2);
  491. qspAddStatName((int)QspStatementType.Play, "PLAY", 0);
  492. qspAddStatName((int)QspStatementType.RefInt, "REFINT", 2);
  493. qspAddStatName((int)QspStatementType.SaveGame, "SAVEGAME", 2);
  494. qspAddStatName((int)QspStatementType.SetTimer, "SETTIMER", 1);
  495. qspAddStatName((int)QspStatementType.ShowActs, "SHOWACTS", 2);
  496. qspAddStatName((int)QspStatementType.ShowInput, "SHOWINPUT", 2);
  497. qspAddStatName((int)QspStatementType.ShowObjs, "SHOWOBJS", 2);
  498. qspAddStatName((int)QspStatementType.ShowVars, "SHOWSTAT", 2);
  499. qspAddStatName((int)QspStatementType.UnSelect, "UNSELECT", 1);
  500. qspAddStatName((int)QspStatementType.UnSelect, "UNSEL", 2);
  501. qspAddStatName((int)QspStatementType.View, "VIEW", 2);
  502. qspAddStatName((int)QspStatementType.Wait, "WAIT", 2);
  503. qspAddStatName((int)QspStatementType.XGoTo, "XGOTO", 2);
  504. qspAddStatName((int)QspStatementType.XGoTo, "XGT", 2);
  505. //Математические операторы и функции
  506. int i;
  507. for (i = 0; i < QSP_OPSLEVELS; ++i) qspOpsNamesCounts[i] = 0;
  508. qspOpMaxLen = 0;
  509. // код оператора, приоритет, тип результата, минимальное кол-во аргументов, максимальное кол-во аргументов, типы аргументов
  510. // 0 - авто
  511. // 1 - строка
  512. // 2 - числовой
  513. qspAddOperation((int)QspFunctionType.Value, 0, 0, 0, 0);
  514. qspAddOperation((int)QspFunctionType.Start, 127, 0, 0, 0);
  515. qspAddOperation((int)QspFunctionType.End, 0, 0, 0, 0);
  516. qspAddOperation((int)QspFunctionType.OpenBracket, 127, 0, 0, 0);
  517. qspAddOperation((int)QspFunctionType.CloseBracket, 0, 0, 0, 0);
  518. qspAddOperation((int)QspFunctionType.Minus, 18, 2, 1, 1, 2);
  519. qspAddOperation((int)QspFunctionType.Add, 14, 0, 2, 2, 0, 0);
  520. qspAddOperation((int)QspFunctionType.Sub, 14, 2, 2, 2, 2, 2);
  521. qspAddOperation((int)QspFunctionType.Mul, 17, 2, 2, 2, 2, 2);
  522. qspAddOperation((int)QspFunctionType.Div, 17, 2, 2, 2, 2, 2);
  523. qspAddOperation((int)QspFunctionType.Mod, 16, 2, 2, 2, 2, 2);
  524. qspAddOperation((int)QspFunctionType.Ne, 10, 2, 2, 2, 0, 0);
  525. qspAddOperation((int)QspFunctionType.Leq, 10, 2, 2, 2, 0, 0);
  526. qspAddOperation((int)QspFunctionType.Geq, 10, 2, 2, 2, 0, 0);
  527. qspAddOperation((int)QspFunctionType.Eq, 10, 2, 2, 2, 0, 0);
  528. qspAddOperation((int)QspFunctionType.Lt, 10, 2, 2, 2, 0, 0);
  529. qspAddOperation((int)QspFunctionType.Gt, 10, 2, 2, 2, 0, 0);
  530. qspAddOperation((int)QspFunctionType.Append, 12, 1, 2, 2, 1, 1);
  531. qspAddOperation((int)QspFunctionType.Comma, 0, 1, 2, 2, 1, 1);
  532. qspAddOperation((int)QspFunctionType.And, 7, 2, 2, 2, 2, 2);
  533. qspAddOperation((int)QspFunctionType.Or, 6, 2, 2, 2, 2, 2);
  534. qspAddOperation((int)QspFunctionType.Loc, 8, 2, 1, 1, 1);
  535. qspAddOperation((int)QspFunctionType.Obj, 8, 2, 1, 1, 1);
  536. qspAddOperation((int)QspFunctionType.Not, 8, 2, 1, 1, 2);
  537. qspAddOperation((int)QspFunctionType.Min, 30, 0, 1, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  538. qspAddOperation((int)QspFunctionType.Max, 30, 0, 1, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  539. qspAddOperation((int)QspFunctionType.Rand, 30, 2, 1, 2, 2, 2);
  540. qspAddOperation((int)QspFunctionType.IIf, 30, 0, 3, 3, 2, 0, 0);
  541. qspAddOperation((int)QspFunctionType.RGB, 30, 2, 3, 4, 2, 2, 2, 2);
  542. qspAddOperation((int)QspFunctionType.Len, 30, 2, 1, 1, 1);
  543. qspAddOperation((int)QspFunctionType.IsNum, 30, 2, 1, 1, 0);
  544. qspAddOperation((int)QspFunctionType.LCase, 30, 1, 1, 1, 1);
  545. qspAddOperation((int)QspFunctionType.UCase, 30, 1, 1, 1, 1);
  546. qspAddOperation((int)QspFunctionType.Input, 30, 1, 1, 1, 1);
  547. qspAddOperation((int)QspFunctionType.Str, 30, 1, 1, 1, 1);
  548. qspAddOperation((int)QspFunctionType.Val, 30, 2, 1, 1, 0);
  549. qspAddOperation((int)QspFunctionType.ArrSize, 30, 2, 1, 1, 1);
  550. qspAddOperation((int)QspFunctionType.IsPlay, 30, 2, 1, 1, 1);
  551. qspAddOperation((int)QspFunctionType.Desc, 30, 1, 1, 1, 1);
  552. qspAddOperation((int)QspFunctionType.Trim, 30, 1, 1, 1, 1);
  553. qspAddOperation((int)QspFunctionType.GetObj, 30, 1, 1, 1, 2);
  554. qspAddOperation((int)QspFunctionType.StrComp, 30, 2, 2, 2, 1, 1);
  555. qspAddOperation((int)QspFunctionType.StrFind, 30, 1, 2, 3, 1, 1, 2);
  556. qspAddOperation((int)QspFunctionType.StrPos, 30, 2, 2, 3, 1, 1, 2);
  557. qspAddOperation((int)QspFunctionType.Mid, 30, 1, 2, 3, 1, 2, 2);
  558. qspAddOperation((int)QspFunctionType.ArrPos, 30, 2, 2, 3, 1, 0, 2);
  559. qspAddOperation((int)QspFunctionType.ArrComp, 30, 2, 2, 3, 1, 0, 2);
  560. qspAddOperation((int)QspFunctionType.Instr, 30, 2, 2, 3, 1, 1, 2);
  561. qspAddOperation((int)QspFunctionType.Replace, 30, 1, 2, 3, 1, 1, 1);
  562. qspAddOperation((int)QspFunctionType.Func, 30, 0, 1, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  563. qspAddOperation((int)QspFunctionType.DynEval, 30, 0, 1, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  564. qspAddOperation((int)QspFunctionType.Rnd, 30, 2, 0, 0);
  565. qspAddOperation((int)QspFunctionType.CountObj, 30, 2, 0, 0);
  566. qspAddOperation((int)QspFunctionType.MsecsCount, 30, 2, 0, 0);
  567. qspAddOperation((int)QspFunctionType.QSPVer, 30, 1, 0, 0);
  568. qspAddOperation((int)QspFunctionType.UserText, 30, 1, 0, 0);
  569. qspAddOperation((int)QspFunctionType.CurLoc, 30, 1, 0, 0);
  570. qspAddOperation((int)QspFunctionType.SelObj, 30, 1, 0, 0);
  571. qspAddOperation((int)QspFunctionType.SelAct, 30, 1, 0, 0);
  572. qspAddOperation((int)QspFunctionType.MainText, 30, 1, 0, 0);
  573. qspAddOperation((int)QspFunctionType.StatText, 30, 1, 0, 0);
  574. qspAddOperation((int)QspFunctionType.CurActs, 30, 1, 0, 0);
  575. /* Names */
  576. qspAddOpName((int)QspFunctionType.CloseBracket, ")", 1);
  577. qspAddOpName((int)QspFunctionType.Add, "+", 1);
  578. qspAddOpName((int)QspFunctionType.Sub, "-", 1);
  579. qspAddOpName((int)QspFunctionType.Mul, "*", 1);
  580. qspAddOpName((int)QspFunctionType.Div, "/", 1);
  581. qspAddOpName((int)QspFunctionType.Mod, "MOD", 1);
  582. qspAddOpName((int)QspFunctionType.Ne, "!", 1);
  583. qspAddOpName((int)QspFunctionType.Ne, "<>", 0);
  584. qspAddOpName((int)QspFunctionType.Leq, "<=", 0);
  585. qspAddOpName((int)QspFunctionType.Leq, "=<", 0);
  586. qspAddOpName((int)QspFunctionType.Geq, ">=", 0);
  587. qspAddOpName((int)QspFunctionType.Geq, "=>", 0);
  588. qspAddOpName((int)QspFunctionType.Eq, "=", 1);
  589. qspAddOpName((int)QspFunctionType.Lt, "<", 1);
  590. qspAddOpName((int)QspFunctionType.Gt, ">", 1);
  591. qspAddOpName((int)QspFunctionType.Append, "&", 1);
  592. qspAddOpName((int)QspFunctionType.Comma, ",", 1);
  593. qspAddOpName((int)QspFunctionType.And, "AND", 1);
  594. qspAddOpName((int)QspFunctionType.Or, "OR", 1);
  595. qspAddOpName((int)QspFunctionType.Loc, "LOC", 1);
  596. qspAddOpName((int)QspFunctionType.Obj, "OBJ", 1);
  597. qspAddOpName((int)QspFunctionType.Not, "NO", 1);
  598. qspAddOpName((int)QspFunctionType.Min, "MIN", 1);
  599. qspAddOpName((int)QspFunctionType.Min, "$MIN", 1);
  600. qspAddOpName((int)QspFunctionType.Max, "MAX", 1);
  601. qspAddOpName((int)QspFunctionType.Max, "$MAX", 1);
  602. qspAddOpName((int)QspFunctionType.Rand, "RAND", 1);
  603. qspAddOpName((int)QspFunctionType.IIf, "IIF", 1);
  604. qspAddOpName((int)QspFunctionType.IIf, "$IIF", 1);
  605. qspAddOpName((int)QspFunctionType.RGB, "RGB", 1);
  606. qspAddOpName((int)QspFunctionType.Len, "LEN", 1);
  607. qspAddOpName((int)QspFunctionType.IsNum, "ISNUM", 1);
  608. qspAddOpName((int)QspFunctionType.LCase, "LCASE", 1);
  609. qspAddOpName((int)QspFunctionType.LCase, "$LCASE", 1);
  610. qspAddOpName((int)QspFunctionType.UCase, "UCASE", 1);
  611. qspAddOpName((int)QspFunctionType.UCase, "$UCASE", 1);
  612. qspAddOpName((int)QspFunctionType.Input, "INPUT", 1);
  613. qspAddOpName((int)QspFunctionType.Input, "$INPUT", 1);
  614. qspAddOpName((int)QspFunctionType.Str, "STR", 1);
  615. qspAddOpName((int)QspFunctionType.Str, "$STR", 1);
  616. qspAddOpName((int)QspFunctionType.Val, "VAL", 1);
  617. qspAddOpName((int)QspFunctionType.ArrSize, "ARRSIZE", 1);
  618. qspAddOpName((int)QspFunctionType.IsPlay, "ISPLAY", 1);
  619. qspAddOpName((int)QspFunctionType.Desc, "DESC", 1);
  620. qspAddOpName((int)QspFunctionType.Desc, "$DESC", 1);
  621. qspAddOpName((int)QspFunctionType.Trim, "TRIM", 1);
  622. qspAddOpName((int)QspFunctionType.Trim, "$TRIM", 1);
  623. qspAddOpName((int)QspFunctionType.GetObj, "GETOBJ", 1);
  624. qspAddOpName((int)QspFunctionType.GetObj, "$GETOBJ", 1);
  625. qspAddOpName((int)QspFunctionType.StrComp, "STRCOMP", 1);
  626. qspAddOpName((int)QspFunctionType.StrFind, "STRFIND", 1);
  627. qspAddOpName((int)QspFunctionType.StrFind, "$STRFIND", 1);
  628. qspAddOpName((int)QspFunctionType.StrPos, "STRPOS", 1);
  629. qspAddOpName((int)QspFunctionType.Mid, "MID", 1);
  630. qspAddOpName((int)QspFunctionType.Mid, "$MID", 1);
  631. qspAddOpName((int)QspFunctionType.ArrPos, "ARRPOS", 1);
  632. qspAddOpName((int)QspFunctionType.ArrComp, "ARRCOMP", 1);
  633. qspAddOpName((int)QspFunctionType.Instr, "INSTR", 1);
  634. qspAddOpName((int)QspFunctionType.Replace, "REPLACE", 1);
  635. qspAddOpName((int)QspFunctionType.Replace, "$REPLACE", 1);
  636. qspAddOpName((int)QspFunctionType.Func, "FUNC", 1);
  637. qspAddOpName((int)QspFunctionType.Func, "$FUNC", 1);
  638. qspAddOpName((int)QspFunctionType.DynEval, "DYNEVAL", 1);
  639. qspAddOpName((int)QspFunctionType.DynEval, "$DYNEVAL", 1);
  640. qspAddOpName((int)QspFunctionType.Rnd, "RND", 1);
  641. qspAddOpName((int)QspFunctionType.CountObj, "COUNTOBJ", 1);
  642. qspAddOpName((int)QspFunctionType.MsecsCount, "MSECSCOUNT", 1);
  643. qspAddOpName((int)QspFunctionType.QSPVer, "QSPVER", 1);
  644. qspAddOpName((int)QspFunctionType.QSPVer, "$QSPVER", 1);
  645. qspAddOpName((int)QspFunctionType.UserText, "USER_TEXT", 1);
  646. qspAddOpName((int)QspFunctionType.UserText, "$USER_TEXT", 1);
  647. qspAddOpName((int)QspFunctionType.UserText, "USRTXT", 1);
  648. qspAddOpName((int)QspFunctionType.UserText, "$USRTXT", 1);
  649. qspAddOpName((int)QspFunctionType.CurLoc, "CURLOC", 1);
  650. qspAddOpName((int)QspFunctionType.CurLoc, "$CURLOC", 1);
  651. qspAddOpName((int)QspFunctionType.SelObj, "SELOBJ", 1);
  652. qspAddOpName((int)QspFunctionType.SelObj, "$SELOBJ", 1);
  653. qspAddOpName((int)QspFunctionType.SelAct, "SELACT", 1);
  654. qspAddOpName((int)QspFunctionType.SelAct, "$SELACT", 1);
  655. qspAddOpName((int)QspFunctionType.MainText, "MAINTXT", 1);
  656. qspAddOpName((int)QspFunctionType.MainText, "$MAINTXT", 1);
  657. qspAddOpName((int)QspFunctionType.StatText, "STATTXT", 1);
  658. qspAddOpName((int)QspFunctionType.StatText, "$STATTXT", 1);
  659. qspAddOpName((int)QspFunctionType.CurActs, "CURACTS", 1);
  660. qspAddOpName((int)QspFunctionType.CurActs, "$CURACTS", 1);
  661. }
  662. static public int qspGetStatCode(string s)
  663. {
  664. if (s.Length == 0)
  665. return (int)QspStatementType.Unknown;
  666. if (s[0] == ':')
  667. return (int)QspStatementType.Label;
  668. if (s[0] == '!')
  669. return (int)QspStatementType.Comment;
  670. int len;
  671. if (s.Length < qspStatMaxLen)
  672. len = s.Length;
  673. else
  674. len = qspStatMaxLen;
  675. string name = s.Substring(0, len).ToUpper().Trim(WhiteSpace);
  676. for (int i = 0; i < QSP_STATSLEVELS; ++i)
  677. {
  678. for (int j = 0; j < qspStatsNamesCounts[i]; j++)
  679. {
  680. if (name.Equals(qspStatsNames[i,j].Name))
  681. return qspStatsNames[i,j].Code;
  682. }
  683. }
  684. return (int)QspStatementType.Unknown;
  685. }
  686. static public int qspGetFunctionCode(string s, bool functionsOnly)
  687. {
  688. if (s.Length == 0)
  689. return (int)QspFunctionType.End;
  690. int len;
  691. if (s.Length < qspOpMaxLen)
  692. len = s.Length;
  693. else
  694. len = qspOpMaxLen;
  695. string name = s.Substring(0, len).ToUpper().Trim(WhiteSpace);
  696. for (int i = 0; i < QSP_OPSLEVELS; ++i)
  697. {
  698. for (int j = 0; j < qspOpsNamesCounts[i]; j++)
  699. {
  700. if ((name.Equals(qspOpsNames[i, j].Name)) &&
  701. (!functionsOnly || (qspOpsNames[i, j].Code >= (int)QspFunctionType.First_Function)))
  702. return qspOpsNames[i, j].Code;
  703. }
  704. }
  705. return (int)QspFunctionType.Unknown;
  706. }
  707. static public QspVariable GetVar(string name)
  708. {
  709. foreach (QspVariable var in vars)
  710. {
  711. if (var.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
  712. return var;
  713. }
  714. return null;
  715. }
  716. static public void AddVar(string name, bool assigned, bool used)
  717. {
  718. QspVariable var = GetVar(name);
  719. if (var == null)
  720. {
  721. var = new QspVariable(name, assigned, used);
  722. vars.Add(var);
  723. }
  724. else
  725. {
  726. if (assigned)
  727. var.Assigned = assigned;
  728. if (used)
  729. var.Used = used;
  730. }
  731. }
  732. static public QspLocationLink GetLocationLink(string name)
  733. {
  734. foreach (QspLocationLink loc in locationLinks)
  735. {
  736. if (loc.LocationName.Equals(name, StringComparison.OrdinalIgnoreCase))
  737. return loc;
  738. }
  739. return null;
  740. }
  741. static public void AddLocationLink(string name, bool exists, bool called)
  742. {
  743. QspLocationLink loc = GetLocationLink(name);
  744. if (loc == null)
  745. {
  746. loc = new QspLocationLink(name, exists, called);
  747. locationLinks.Add(loc);
  748. }
  749. else
  750. {
  751. if (exists)
  752. loc.LocationExists = exists;
  753. if (called)
  754. loc.LocationCalled = called;
  755. }
  756. }
  757. static public QspObj GetObj(string name)
  758. {
  759. foreach (QspObj obj in objects)
  760. {
  761. if (obj.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
  762. return obj;
  763. }
  764. return null;
  765. }
  766. static public void AddObj(string name, bool added, bool removed)
  767. {
  768. QspObj obj = GetObj(name);
  769. if (obj == null)
  770. {
  771. obj = new QspObj(name, added, removed);
  772. objects.Add(obj);
  773. }
  774. else
  775. {
  776. if (added)
  777. obj.Added = added;
  778. if (removed)
  779. obj.Removed = removed;
  780. }
  781. }
  782. static public QspAct GetAct(string name)
  783. {
  784. foreach (QspAct act in acts)
  785. {
  786. if (act.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
  787. return act;
  788. }
  789. return null;
  790. }
  791. static public void AddAct(string name, bool added, bool removed)
  792. {
  793. QspAct act = GetAct(name);
  794. if (act == null)
  795. {
  796. act = new QspAct(name, added, removed);
  797. acts.Add(act);
  798. }
  799. else
  800. {
  801. if (added)
  802. act.Added = added;
  803. if (removed)
  804. act.Removed = removed;
  805. }
  806. }
  807. static public void SetConfig(List<string> callerVars, List<string> systemVars, bool EnableCurlyParsing)
  808. {
  809. callerVariables = callerVars;
  810. systemVariables = systemVars;
  811. curlyParsing = EnableCurlyParsing;
  812. }
  813. static public bool IsNumber(String s)
  814. {
  815. foreach (char c in s.ToCharArray())
  816. {
  817. if (Array.IndexOf(Digits, c) == INVALID_INDEX)
  818. return false;
  819. }
  820. return true;
  821. }
  822. static public bool ListContainsIgnoreCase(List<string> stringList, string value)
  823. {
  824. bool contains = null != stringList.Find(delegate(string str)
  825. {
  826. return str.Equals(value, StringComparison.OrdinalIgnoreCase);
  827. });
  828. return contains;
  829. }
  830. static public string GenerateCsvName(string FileName)
  831. {
  832. string result = FileName;
  833. if (result.EndsWith(".txt"))
  834. result = result.Substring(0, result.Length - 4);
  835. result = result + ".csv";
  836. return result;
  837. }
  838. static public bool ExportToCsv(string srcFile, string delimiter)
  839. {
  840. //Выгружаем исходный код в CSV
  841. //4 колонки: номер+локация, оригинал, место для перевода, место для комментария
  842. string dstFile = GenerateCsvName(srcFile);
  843. StreamReader fi = null;
  844. if (!OpenStreamForReading(ref fi, srcFile))
  845. {
  846. return false;
  847. }
  848. StreamWriter fo = null;
  849. if (!OpenStreamForWriting(ref fo, dstFile))
  850. {
  851. fi.Close();
  852. return false;
  853. }
  854. string line;
  855. int line_counter = 0;
  856. int quoted_line_counter = 0;
  857. bool inside = false;
  858. string locName = null;
  859. int quote = (int)QuoteType.None;
  860. string quotedText = "";
  861. bool quotedTextCompleted = false;
  862. while ((line = fi.ReadLine()) != null)
  863. {
  864. line_counter++;
  865. line = line.Trim(WhiteSpace);
  866. if ((line.Length > 0) && (line[0] == '#'))
  867. {
  868. //имя локации
  869. locName = line.Substring(1).Trim(WhiteSpace);
  870. inside = true;
  871. }
  872. else if ((line.Length > 38) && line.StartsWith("--- ") && line.EndsWith(" ---------------------------------"))
  873. {
  874. inside = false;
  875. locName = null;
  876. }
  877. else if (inside)
  878. {
  879. //Разбираем только строки внутри локаций
  880. int pos = 0;
  881. //Разбор строки
  882. while (pos < line.Length)
  883. {
  884. char c = line[pos];
  885. if (c == '\'')
  886. {
  887. //Апостроф
  888. if (quote == (int)QuoteType.None)
  889. {
  890. quote = (int)QuoteType.Single;
  891. quotedText = "";
  892. }
  893. else if (quote == (int)QuoteType.Single)
  894. {
  895. if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
  896. {
  897. //Экранированный апостроф
  898. pos++;
  899. quotedText += c;
  900. }
  901. else
  902. {
  903. quote = (int)QuoteType.None;
  904. quotedTextCompleted = true;
  905. }
  906. }
  907. else
  908. {
  909. quotedText += c;
  910. }
  911. }
  912. else if (c == '"')
  913. {
  914. //Кавычка
  915. if (quote == (int)QuoteType.None)
  916. {
  917. quote = (int)QuoteType.Double;
  918. quotedText = "";
  919. }
  920. else if (quote == (int)QuoteType.Double)
  921. {
  922. if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
  923. {
  924. //Экранированная кавычка
  925. pos++;
  926. quotedText += c;
  927. }
  928. else
  929. {
  930. quote = (int)QuoteType.None;
  931. quotedTextCompleted = true;
  932. }
  933. }
  934. else
  935. {
  936. quotedText += c;
  937. }
  938. }
  939. else if (quote != (int)QuoteType.None)
  940. {
  941. //Строка текста внутри кавычек или апострофов
  942. quotedText += c;
  943. }
  944. else if (c == '{')
  945. {
  946. //Пропускаем содержимое фигурных скобок
  947. int curlyLevel = 1;
  948. pos++;
  949. int curlyQuote = (int)QuoteType.None;
  950. while (pos < line.Length)
  951. {
  952. char c2 = line[pos];
  953. if (c2 == '\'')
  954. {
  955. //Апостроф
  956. if (curlyQuote == (int)QuoteType.None)
  957. {
  958. curlyQuote = (int)QuoteType.Single;
  959. }
  960. else if (curlyQuote == (int)QuoteType.Single)
  961. {
  962. if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
  963. {
  964. //Экранированный апостроф
  965. pos++;
  966. }
  967. else
  968. {
  969. curlyQuote = (int)QuoteType.None;
  970. }
  971. }
  972. }
  973. else if (c2 == '"')
  974. {
  975. //Кавычка
  976. if (curlyQuote == (int)QuoteType.None)
  977. {
  978. curlyQuote = (int)QuoteType.Double;
  979. }
  980. else if (curlyQuote == (int)QuoteType.Double)
  981. {
  982. if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
  983. {
  984. //Экранированная кавычка
  985. pos++;
  986. }
  987. else
  988. {
  989. curlyQuote = (int)QuoteType.None;
  990. }
  991. }
  992. }
  993. else if (curlyQuote == (int)QuoteType.None)
  994. {
  995. if (c2 == '{')
  996. {
  997. curlyLevel++;
  998. }
  999. else if (c2 == '}')
  1000. {
  1001. curlyLevel--;
  1002. if (curlyLevel == 0)
  1003. break;
  1004. }
  1005. }
  1006. pos++;
  1007. }
  1008. }
  1009. if (quotedTextCompleted)
  1010. {
  1011. //Формируем строку для csv-файла
  1012. //4 колонки: номер+локация, оригинал, место для перевода, место для комментария
  1013. if (quotedText.Trim(WhiteSpace).Length > 0)
  1014. {
  1015. quoted_line_counter++;
  1016. string csv_line = "";
  1017. csv_line += CsvEscape(quoted_line_counter.ToString() + ":" + locName) + delimiter;
  1018. csv_line += CsvEscape(quotedText) + delimiter;
  1019. csv_line += CsvEscape("") + delimiter;
  1020. csv_line += CsvEscape("");
  1021. //Записываем строку в csv-файл
  1022. fo.WriteLine(csv_line);
  1023. }
  1024. quotedTextCompleted = false;
  1025. }
  1026. pos++;
  1027. }
  1028. }
  1029. }
  1030. fi.Close();
  1031. fo.Close();
  1032. return true;
  1033. }
  1034. static public string CsvEscape(string src)
  1035. {
  1036. //Форматируем строку для записи в csv-файл
  1037. string result = "\"" + src.Replace("\"", "\"\"") + "\"";
  1038. return result;
  1039. }
  1040. static public string CsvUnEscape(string src)
  1041. {
  1042. //Преобразовываем строку из csv-формата в обычный текст
  1043. string result = src;
  1044. if (src.StartsWith("\""))
  1045. {
  1046. result = result.Substring(1, result.Length - 2);
  1047. result = result.Replace("\"\"", "\"");
  1048. }
  1049. return result;
  1050. }
  1051. static public bool TranslateFromCsv(string srcFile, string suffix, bool IgnoreEmptyTranslations, string delimiter)
  1052. {
  1053. //Создаем перевод на основе загруженного файла и CSV
  1054. //Проверяем соответствие номера, локации, оригинального текста, в случае несовпадения выдаем ошибку и не сохраняем файл
  1055. //Для пустых строк заполняем текстом оригинала, либо выдаем ошибку - в зависимости от настроек.
  1056. string dstFile = srcFile;
  1057. if (dstFile.EndsWith(".txt"))
  1058. dstFile = dstFile.Substring(0, dstFile.Length - 4);
  1059. dstFile = dstFile + suffix + ".txt";
  1060. string csvFile = GenerateCsvName(srcFile);
  1061. StreamReader fi_src = null;
  1062. if (!OpenStreamForReading(ref fi_src, srcFile))
  1063. {
  1064. return false;
  1065. }
  1066. StreamReader fi_csv = null;
  1067. if (!OpenStreamForReading(ref fi_csv, csvFile))
  1068. {
  1069. fi_src.Close();
  1070. return false;
  1071. }
  1072. StreamWriter fo = null;
  1073. if (!OpenStreamForWriting(ref fo, dstFile))
  1074. {
  1075. fi_src.Close();
  1076. fi_csv.Close();
  1077. return false;
  1078. }
  1079. string line;
  1080. string line_cut;
  1081. int line_counter = 0;
  1082. int quoted_line_counter = 0;
  1083. bool inside = false;
  1084. string locName = null;
  1085. int quote = (int)QuoteType.None;
  1086. string quotedText = "";
  1087. bool quotedTextCompleted = false;
  1088. string rawText = "";
  1089. bool aborted = false;
  1090. while ((line = fi_src.ReadLine()) != null)
  1091. {
  1092. line_counter++;
  1093. line_cut = line.Trim(WhiteSpace);
  1094. if ((line_cut.Length > 0) && (line_cut[0] == '#'))
  1095. {
  1096. //имя локации
  1097. locName = line_cut.Substring(1).Trim(WhiteSpace);
  1098. inside = true;
  1099. fo.WriteLine(line);
  1100. }
  1101. else if ((line_cut.Length > 38) && line_cut.StartsWith("--- ") && line_cut.EndsWith(" ---------------------------------"))
  1102. {
  1103. inside = false;
  1104. locName = null;
  1105. fo.WriteLine(line);
  1106. }
  1107. else if (inside)
  1108. {
  1109. //Разбираем только строки внутри локаций
  1110. int pos = 0;
  1111. //Разбор строки
  1112. while (pos < line.Length)
  1113. {
  1114. char c = line[pos];
  1115. if (c == '\'')
  1116. {
  1117. //Апостроф
  1118. if (quote == (int)QuoteType.None)
  1119. {
  1120. quote = (int)QuoteType.Single;
  1121. quotedText = "";
  1122. rawText += c;
  1123. }
  1124. else if (quote == (int)QuoteType.Single)
  1125. {
  1126. if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
  1127. {
  1128. //Экранированный апостроф
  1129. pos++;
  1130. quotedText += c;
  1131. }
  1132. else
  1133. {
  1134. quote = (int)QuoteType.None;
  1135. quotedTextCompleted = true;
  1136. }
  1137. }
  1138. else
  1139. {
  1140. quotedText += c;
  1141. }
  1142. }
  1143. else if (c == '"')
  1144. {
  1145. //Кавычка
  1146. if (quote == (int)QuoteType.None)
  1147. {
  1148. quote = (int)QuoteType.Double;
  1149. quotedText = "";
  1150. rawText += c;
  1151. }
  1152. else if (quote == (int)QuoteType.Double)
  1153. {
  1154. if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
  1155. {
  1156. //Экранированная кавычка
  1157. pos++;
  1158. quotedText += c;
  1159. }
  1160. else
  1161. {
  1162. quote = (int)QuoteType.None;
  1163. quotedTextCompleted = true;
  1164. }
  1165. }
  1166. else
  1167. {
  1168. quotedText += c;
  1169. }
  1170. }
  1171. else if (quote != (int)QuoteType.None)
  1172. {
  1173. //Строка текста внутри кавычек или апострофов
  1174. quotedText += c;
  1175. }
  1176. else if (c == '{')
  1177. {
  1178. //Пропускаем содержимое фигурных скобок
  1179. int curlyLevel = 1;
  1180. rawText += c;
  1181. pos++;
  1182. int curlyQuote = (int)QuoteType.None;
  1183. while (pos < line.Length)
  1184. {
  1185. char c2 = line[pos];
  1186. rawText += c2;
  1187. if (c2 == '\'')
  1188. {
  1189. //Апостроф
  1190. if (curlyQuote == (int)QuoteType.None)
  1191. {
  1192. curlyQuote = (int)QuoteType.Single;
  1193. }
  1194. else if (curlyQuote == (int)QuoteType.Single)
  1195. {
  1196. if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
  1197. {
  1198. //Экранированный апостроф
  1199. rawText += line[pos + 1];
  1200. pos++;
  1201. }
  1202. else
  1203. {
  1204. curlyQuote = (int)QuoteType.None;
  1205. }
  1206. }
  1207. }
  1208. else if (c2 == '"')
  1209. {
  1210. //Кавычка
  1211. if (curlyQuote == (int)QuoteType.None)
  1212. {
  1213. curlyQuote = (int)QuoteType.Double;
  1214. }
  1215. else if (curlyQuote == (int)QuoteType.Double)
  1216. {
  1217. if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
  1218. {
  1219. //Экранированная кавычка
  1220. rawText += line[pos + 1];
  1221. pos++;
  1222. }
  1223. else
  1224. {
  1225. curlyQuote = (int)QuoteType.None;
  1226. }
  1227. }
  1228. }
  1229. else if (curlyQuote == (int)QuoteType.None)
  1230. {
  1231. if (c2 == '{')
  1232. {
  1233. curlyLevel++;
  1234. }
  1235. else if (c2 == '}')
  1236. {
  1237. curlyLevel--;
  1238. if (curlyLevel == 0)
  1239. break;
  1240. }
  1241. }
  1242. pos++;
  1243. }
  1244. }
  1245. else
  1246. {
  1247. rawText += c;
  1248. }
  1249. if (quotedTextCompleted)
  1250. {
  1251. //Читаем строку из файла перевода
  1252. string translation = quotedText;
  1253. if (quotedText.Trim(WhiteSpace).Length > 0)
  1254. {
  1255. translation = "";
  1256. quoted_line_counter++;
  1257. bool csvLineCompleted = false;
  1258. string csv_line = null;
  1259. int valuesCount = 0;
  1260. string thirdValue = "";
  1261. int csvQuote = (int)QuoteType.None;
  1262. string csvText = "";
  1263. bool csvValueCompleted = false;
  1264. int csvLineIndex = INVALID_INDEX;
  1265. string csvLocName = "";
  1266. string csvOriginalLine = "";
  1267. while (!csvLineCompleted && ((csv_line = fi_csv.ReadLine()) != null))
  1268. {
  1269. int csvPos = 0;
  1270. //Разбор строки
  1271. while (csvPos < csv_line.Length)
  1272. {
  1273. int newValuesCount = valuesCount;
  1274. char c3 = csv_line[csvPos];
  1275. if (c3 == '"')
  1276. {
  1277. csvText += c3;
  1278. //Кавычка
  1279. if (csvQuote == (int)QuoteType.None)
  1280. {
  1281. csvQuote = (int)QuoteType.Double;
  1282. }
  1283. else if (csvQuote == (int)QuoteType.Double)
  1284. {
  1285. if ((csvPos + 1 < csv_line.Length) && (csv_line[csvPos + 1] == '"'))
  1286. {
  1287. //Экранированная кавычка
  1288. csvText += csv_line[csvPos + 1];
  1289. csvPos++;
  1290. }
  1291. else
  1292. {
  1293. csvQuote = (int)QuoteType.None;
  1294. }
  1295. }
  1296. }
  1297. else if (csvQuote != (int)QuoteType.None)
  1298. {
  1299. //Строка текста внутри кавычек
  1300. csvText += c3;
  1301. }
  1302. else if (c3.ToString() == delimiter)
  1303. {
  1304. newValuesCount++;
  1305. csvValueCompleted = true;
  1306. }
  1307. else
  1308. {
  1309. csvText += c3;
  1310. }
  1311. if ((csvQuote == (int)QuoteType.None) && (csvPos == csv_line.Length - 1))
  1312. {
  1313. newValuesCount++;
  1314. csvValueCompleted = true;
  1315. }
  1316. if (csvValueCompleted)
  1317. {
  1318. for (int iter = valuesCount + 1; iter <= newValuesCount; iter++)
  1319. {
  1320. csvText = CsvUnEscape(csvText.Trim(WhiteSpace));
  1321. if (iter == 1) //Первая колонка - имя локации и номер строки
  1322. {
  1323. string[] csvFirst = csvText.Split(":".ToCharArray());
  1324. if (csvFirst.Length == 2)
  1325. {
  1326. csvLineIndex = Convert.ToInt32(csvFirst[0]);
  1327. csvLocName = csvFirst[1];
  1328. }
  1329. }
  1330. else if (iter == 2) //Вторая колонка - оригинал
  1331. {
  1332. csvOriginalLine = csvText;
  1333. }
  1334. else if (iter == 3) //Третья колонка - перевод
  1335. {
  1336. thirdValue = csvText;
  1337. }
  1338. csvText = "";
  1339. }
  1340. csvValueCompleted = false;
  1341. valuesCount = newValuesCount;
  1342. }
  1343. csvPos++;
  1344. }
  1345. if (csvQuote == (int)QuoteType.None)
  1346. {
  1347. csvLineCompleted = true;
  1348. }
  1349. else
  1350. {
  1351. csvText += Environment.NewLine;
  1352. }
  1353. }
  1354. if ((csv_line == null) || (csvLineCompleted &&
  1355. ((csvLocName != locName) || (quoted_line_counter != csvLineIndex) || (csvOriginalLine != quotedText))))
  1356. {
  1357. SubmitError("CSV-file does not match the original! Generate it again.", INVALID_INDEX);
  1358. aborted = true;
  1359. break;
  1360. }
  1361. if (!csvLineCompleted)
  1362. {
  1363. SubmitError("CSV-file damaged! Line number: " + quoted_line_counter.ToString(), INVALID_INDEX);
  1364. aborted = true;
  1365. break;
  1366. }
  1367. translation = thirdValue;
  1368. if (translation.Length == 0)
  1369. {
  1370. if (IgnoreEmptyTranslations)
  1371. {
  1372. translation = quotedText;
  1373. }
  1374. else
  1375. {
  1376. SubmitError("Line number " + quoted_line_counter + " is not converted!", INVALID_INDEX);
  1377. aborted = true;
  1378. break;
  1379. }
  1380. }
  1381. }
  1382. rawText += translation;
  1383. rawText += c;
  1384. quotedTextCompleted = false;
  1385. }
  1386. pos++;
  1387. }
  1388. if (aborted)
  1389. break;
  1390. if (quote == (int)QuoteType.None)
  1391. {
  1392. //Записываем строку в файл перевода
  1393. fo.WriteLine(rawText);
  1394. rawText = "";
  1395. }
  1396. }
  1397. else
  1398. {
  1399. fo.WriteLine(line);
  1400. }
  1401. }
  1402. fi_src.Close();
  1403. fi_csv.Close();
  1404. fo.Close();
  1405. if (aborted)
  1406. {
  1407. //Убить корявый перевод
  1408. File.Delete(dstFile);
  1409. }
  1410. return !aborted;
  1411. }
  1412. static public bool OpenStreamForReading(ref StreamReader fi, string file)
  1413. {
  1414. bool result = false;
  1415. try
  1416. {
  1417. fi = new StreamReader(file, Encoding.Default);
  1418. result = true;
  1419. }
  1420. catch (Exception e)
  1421. {
  1422. SubmitError("File \"" + file + "\" cannot be opened for reading (it can be opened by another program).", INVALID_INDEX);
  1423. result = false;
  1424. }
  1425. return result;
  1426. }
  1427. static public bool OpenStreamForWriting(ref StreamWriter fo, string file)
  1428. {
  1429. bool result = false;
  1430. try
  1431. {
  1432. fo = new StreamWriter(file, false, Encoding.Default);
  1433. result = true;
  1434. }
  1435. catch (Exception e)
  1436. {
  1437. SubmitError("File \"" + file + "\" cannot be opened for writing (it can be opened by another program).", INVALID_INDEX);
  1438. result = false;
  1439. }
  1440. return result;
  1441. }
  1442. }
  1443. }