1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Text;
- using System.Threading;
- using System.ComponentModel;
- namespace Analyser
- {
- public class Location : Common
- {
- QSPGameCode m_gamecode;
- string m_name;
- int m_line;
- bool m_start; //Стартовая локация
- List<string> location_codeline_text;
- Dictionary<int, int> location_codeline_level;
- int currentLine;
- bool currentRoot;
- enum ControlBlockType
- {
- None,
- SL_If,
- SL_Else,
- SL_Act,
- ML_If,
- ML_Else,
- ML_Act,
- IfCondition,
- ElseIfCondition,
- ActCondition
- }
-
- struct ControlLine
- {
- public ControlBlockType controlBlock;
- public int line;
- }
- public Location(QSPGameCode code, string name, int line, bool start)
- {
- m_gamecode = code;
- m_name = name;
- m_line = line;
- m_start = start;
- location_codeline_text = null;
- location_codeline_level = null;
- }
- public string GetName()
- {
- return m_name;
- }
- public int GetLine()
- {
- return m_line;
- }
- public int GetCodeLinesCount()
- {
- return location_codeline_text.Count;
- }
- public void GetCodeLine(int lineNum, ref string text, ref int level)
- {
- //Нужно для утилиты форматирования
- int realNum = lineNum + 1;
- text = location_codeline_text[lineNum];
- if (location_codeline_level.ContainsKey(realNum))
- level = location_codeline_level[realNum];
- else
- level = INVALID_INDEX;
- return;
- }
- new void SubmitError(string text, int line)
- {
- if (currentRoot)
- Common.SubmitError(text, line);
- else
- Common.SubmitError(text, currentLine);
- }
- new void SubmitWarning(string text, int line)
- {
- if (currentRoot)
- Common.SubmitWarning(text, line);
- else
- Common.SubmitWarning(text, currentLine);
- }
- bool qspCompileExprPushOpCode(ref int[] opStack, ref int opSp, ref int[] argStack, ref int argSp, int opCode)
- {
- if ((opSp == QSP_STACKSIZE - 1) || (argSp == QSP_STACKSIZE - 1))
- {
- SubmitError("Quite complicated expression", currentLine);
- return false;
- }
- opStack[++opSp] = opCode;
- argStack[++argSp] = (opCode < (int)QspFunctionType.First_Function) ? qspOps[opCode].MinArgsCount : 0;
- return true;
- }
- bool qspAppendToCompiled(ref int itemsCount)
- {
- if (itemsCount == QSP_MAXITEMS)
- {
- SubmitError("Quite many arguments in the expression", currentLine);
- return false;
- }
- ++itemsCount;
- return true;
- }
- public bool ParseLocation(List<string> code, bool root)
- {
- int quote = (int)QuoteType.None;
- if (root)
- {
- currentRoot = true;
- currentLine = 0;
- location_codeline_text = new List<string>(code);
- location_codeline_level = new Dictionary<int, int>();
- }
- //Склеиваем строки
- List<int> lineIndexes = new List<int>();
- List<string> escapedLines = new List<string>();
- int linesCount = code.Count;
- int oldLine = 0;
- int curLine = 0;
- int curlyLevel = 0;
- string extraLine = "";
- while (curLine < linesCount)
- {
- string line = code.ToArray()[curLine].Trim(WhiteSpace);
- int pos = 0;
- while (pos < line.Length)
- {
- char c = line[pos];
- if (c == '\'')
- {
- //Апостроф
- if (quote == (int)QuoteType.None)
- {
- quote = (int)QuoteType.Single;
- }
- else if (quote == (int)QuoteType.Single)
- {
- if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
- {
- //Экранированный апостроф
- pos++;
- }
- else
- {
- quote = (int)QuoteType.None;
- }
- }
- }
- else if (c == '"')
- {
- //Кавычка
- if (quote == (int)QuoteType.None)
- {
- quote = (int)QuoteType.Double;
- }
- else if (quote == (int)QuoteType.Double)
- {
- if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
- {
- //Экранированная кавычка
- pos++;
- }
- else
- {
- quote = (int)QuoteType.None;
- }
- }
- }
- else if (quote == (int)QuoteType.None)
- {
- if (c == '{')
- {
- curlyLevel++;
- }
- else if (c == '}')
- {
- if (curlyLevel == 0)
- {
- SubmitError("Closing curly brace without opening one", oldLine + 1);
- return false;
- }
- curlyLevel--;
- }
- }
- pos++;
- }
- if ((curlyLevel > 0) || (quote != (int)QuoteType.None) || line.EndsWith(" _"))
- {
- if (line.EndsWith(" _"))
- line = line.Substring(0, line.Length - 2);
- extraLine += line;
- if (curlyLevel > 0)
- extraLine += "\n";//Вставляем разделитель для строк, потом по нему "разобьем" строки
- if (curLine == linesCount - 1)
- {
- lineIndexes.Add(oldLine + 1);
- string escaped = extraLine + line;
- escapedLines.Add(escaped.Trim(WhiteSpace));
- }
- }
- else
- {
- lineIndexes.Add(oldLine + 1);
- string escaped = extraLine + line;
- escapedLines.Add(escaped.Trim(WhiteSpace));
- oldLine = curLine + 1;
- extraLine = "";
- }
- curLine++;
- }
- //Проверка на незакрытые в конце локации многострочные строки
- if (quote != (int)QuoteType.None)
- {
- SubmitError("Unclosed string", oldLine + 1);
- return false;
- }
- //Проверка на незакрытые в конце локации фигурные скобки
- if (curlyLevel > 0)
- {
- SubmitError("Unclosed curly bracket", oldLine + 1);
- return false;
- }
- //TODO
- // FOR
- // перечисления asd|12|ddd
- //Разбираем код
- int lineNum = 0;
- int linePlainNum = 0;
- string block = "";
- string quotedText = "";
- int controlBlock = (int)ControlBlockType.None;
- Stack<ControlLine> ControlStack = new Stack<ControlLine>();
- List<string> blockGroup = new List<string>();
- List<bool> blockInGroupIsText = new List<bool>();
- int groupInnerCounter = 0;
- bool blockStarted = false;
- bool blockCompleted = false;
- bool blockGroupStarted = false;
- bool blockGroupCompleted = false;
- bool quotedTextCompleted = false;
- string rawText = "";
- string debugText = "";
- foreach (string line in escapedLines)
- {
- lineNum = lineIndexes[linePlainNum];
- linePlainNum++;
- int startIndentLevel = 0;
- int endIndentLevel = 0;
- if (currentRoot)
- {
- currentLine = lineNum;
- //Вычисляем уровень вложенности(для утилиты форматирования кода)
- int stackSize = ControlStack.Count;
- if (stackSize > 0)
- startIndentLevel = stackSize;
- }
- int pos = 0;
- int firstSymbolPos = INVALID_INDEX;
- int blockStartPos = INVALID_INDEX;
- int lastIfPos = INVALID_INDEX;
- int lastActPos = INVALID_INDEX;
- int bracketLevel = 0;
- bool comment = false;
- bool label = false;
- string labelText = "";
- bool singleBlockGroup = false;
-
- //Разбор строки
- while (pos < line.Length)
- {
- bool appendDelimiter = false;
- String delimiterToAppend = "";
- char c = line[pos];
- if ((c.ToString().IndexOfAny(WhiteSpace) != 0) && (firstSymbolPos == INVALID_INDEX))
- {
- firstSymbolPos = pos;
- }
- if (c == '\'')
- {
- //Апостроф
- if (quote == (int)QuoteType.None)
- {
- quote = (int)QuoteType.Single;
- quotedText = "";
- if (blockStarted && !comment)
- blockCompleted = true;
- //для отладки
- if (rawText.Length == 0)
- rawText += c;
- else
- rawText += Environment.NewLine + c;
- }
- else if (quote == (int)QuoteType.Single)
- {
- if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
- {
- //Экранированный апостроф
- pos++;
- quotedText += c;
- }
- else
- {
- quote = (int)QuoteType.None;
- if (!comment && !label)
- quotedTextCompleted = true;
- }
- //для отладки
- rawText += c;
- }
- else
- {
- quotedText += c;
- //для отладки
- rawText += c;
- }
- }
- else if (c == '"')
- {
- //Кавычка
- if (quote == (int)QuoteType.None)
- {
- quote = (int)QuoteType.Double;
- quotedText = "";
- if (blockStarted && !comment)
- blockCompleted = true;
- //для отладки
- if (rawText.Length == 0)
- rawText += c;
- else
- rawText += Environment.NewLine + c;
- }
- else if (quote == (int)QuoteType.Double)
- {
- if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
- {
- //Экранированная кавычка
- pos++;
- quotedText += c;
- }
- else
- {
- quote = (int)QuoteType.None;
- if (!comment && !label)
- quotedTextCompleted = true;
- }
- //для отладки
- rawText += c;
- }
- else
- {
- quotedText += c;
- //для отладки
- rawText += c;
- }
- }
- else if (comment)
- {
- //Здесь игнорируем все до самого конца строки, но учитываем переводы строк внутри кавычек и апострофов.
- }
- else if (quote != (int)QuoteType.None)
- {
- //Строка текста внутри кавычек или апострофов
- quotedText += c;
- //для отладки
- rawText += c;
- }
- else if (c == '{')
- {
- if (blockStarted && !comment)
- blockCompleted = true;
- //Записываем содержимое фигурных скобок
- string curlyText = "";
- curlyLevel = 1;
- pos++;
- int curlyQuote = (int)QuoteType.None;
- while (pos < line.Length)
- {
- char c2 = line[pos];
- if (c2 == '\'')
- {
- //Апостроф
- if (curlyQuote == (int)QuoteType.None)
- {
- curlyQuote = (int)QuoteType.Single;
- }
- else if (curlyQuote == (int)QuoteType.Single)
- {
- if ((pos + 1 < line.Length) && (line[pos + 1] == '\''))
- {
- //Экранированный апостроф
- curlyText += c2;
- pos++;
- c2 = line[pos];
- }
- else
- {
- curlyQuote = (int)QuoteType.None;
- }
- }
- }
- else if (c2 == '"')
- {
- //Кавычка
- if (curlyQuote == (int)QuoteType.None)
- {
- curlyQuote = (int)QuoteType.Double;
- }
- else if (curlyQuote == (int)QuoteType.Double)
- {
- if ((pos + 1 < line.Length) && (line[pos + 1] == '"'))
- {
- //Экранированная кавычка
- curlyText += c2;
- pos++;
- c2 = line[pos];
- }
- else
- {
- curlyQuote = (int)QuoteType.None;
- }
- }
- }
- else if (curlyQuote == (int)QuoteType.None)
- {
- if (c2 == '{')
- {
- curlyLevel++;
- }
- else if (c2 == '}')
- {
- curlyLevel--;
- if (curlyLevel == 0)
- break;
- }
- }
- curlyText += c2;
- pos++;
- }
- if (curlyLevel > 0)
- {
- SubmitError("Internal error of the analyzer - unclosed curly bracket \"{\"", currentLine);
- break;
- }
- if (curlyParsing)
- {
- //Парсим содержимое фигурных скобок
- List<string> curlyLines = new List<string>(curlyText.Split('\n'));
- currentRoot = false;
- ParseLocation(curlyLines, currentRoot);
- currentRoot = root;
- //Добавляем пустую "строку в кавычках", чтобы анализатор не ругался на отсутствие параметра
- quotedText = "";
- }
- else
- {
- quotedText = curlyText;
- }
- quotedTextCompleted = true;
- }
- else
- {
- //Обычные символы
- if (label)
- {
- if (c == '&')
- {
- if (labelText.Trim(WhiteSpace).Equals(":"))
- {
- SubmitError("Empty label", lineNum);
- return false;
- }
- if (quote != (int)QuoteType.None)
- {
- SubmitError("Unclosed string in the label name", lineNum);
- return false;
- }
- label = false;
- }
- else
- {
- labelText += c;
- }
- }
- else if ((c == ':') && ((controlBlock == (int)ControlBlockType.IfCondition) ||
- (controlBlock == (int)ControlBlockType.ElseIfCondition)))
- {
- //Разбор условия
- if (blockStarted)
- blockCompleted = true;
- blockGroupCompleted = true;
- //Двоеточие после условия
- if ((pos == line.Length - 1))
- {
- //В конце строки - многострочный IF или ELSEIF
- if (firstSymbolPos == lastIfPos)
- {
- if (controlBlock == (int)ControlBlockType.IfCondition)
- {
- ControlLine cline;
- cline.line = lineNum;
- cline.controlBlock = ControlBlockType.ML_If;
- ControlStack.Push(cline);
- }
- else
- {
- ControlLine cline = ControlStack.Pop();
- if (cline.controlBlock != ControlBlockType.ML_If)
- {
- SubmitError("ELSEIF without IF", lineNum);
- return false;
- }
- cline.line = lineNum;
- ControlStack.Push(cline);
- }
- controlBlock = (int)ControlBlockType.ML_If;
- }
- else
- {
- if (controlBlock == (int)ControlBlockType.IfCondition)
- SubmitError("Multiline IF should be placed at the beginning of the line", lineNum);
- else
- SubmitError("Multiline ELSEIF should be placed at the beginning of the line", lineNum);
- return false;
- }
- }
- else if (controlBlock == (int)ControlBlockType.IfCondition)
- {
- //Строка не заканчивается - однострочный IF
- if (controlBlock == (int)ControlBlockType.IfCondition)
- {
- ControlLine cline;
- cline.line = lineNum;
- cline.controlBlock = ControlBlockType.SL_If;
- ControlStack.Push(cline);
- controlBlock = (int)cline.controlBlock;
- groupInnerCounter = 0;
- }
- else
- {
- SubmitError("ELSEIF cannot be used in single line IF", lineNum);
- return false;
- }
- }
- else
- {
- SubmitError("An operator cannot be placed after colon\":\" in multiline ELSEIF", lineNum);
- return false;
- }
- }
- else if ((c == ':') && (block == "else"))
- {
- SubmitError("ELSE with :", lineNum);
- return false;
- }
- else if ((c == ':') && (controlBlock == (int)ControlBlockType.ActCondition))
- {
- //Разбор аргумента
- if (blockStarted)
- blockCompleted = true;
- blockGroupCompleted = true;
- //Двоеточие после ACT
- if (pos == line.Length - 1)
- {
- //В конце строки - многострочный ACT
- if (firstSymbolPos == lastActPos)
- {
- controlBlock = (int)ControlBlockType.ML_Act;
- ControlLine cline;
- cline.line = lineNum;
- cline.controlBlock = ControlBlockType.ML_Act;
- ControlStack.Push(cline);
- }
- else
- {
- SubmitError("Multiline ACT should be placed at the beginning of the line", lineNum);
- return false;
- }
- }
- else
- {
- //Строка не заканчивается - однострочный ACT
- controlBlock = (int)ControlBlockType.SL_Act;
- groupInnerCounter = 0;
- }
- }
- else if (!comment && (c == '!') && !blockGroupStarted && !blockStarted)
- {
- //Начало комментария
- comment = true;
- }
- else if ((c == ':') && (firstSymbolPos == pos))
- {
- //Начало метки
- label = true;
- }
- else if (c.ToString().IndexOfAny(Delimiters) == 0)
- {
- if ((c == '&') && (bracketLevel == 0))
- {
- if (controlBlock == (int)ControlBlockType.IfCondition)
- {
- //В условии IF недопустимо использование "&" вне скобок
- SubmitError("Redundant \"&\": perhaps should be \"AND\"", lineNum);
- return false;
- }
- else if (controlBlock == (int)ControlBlockType.ActCondition)
- {
- //В названии ACT недопустимо использование "&" вне скобок
- SubmitError("Redundant \"&\"", lineNum);
- return false;
- }
- else
- {
- if (blockStarted)
- blockCompleted = true;
- if (blockGroupStarted)
- blockGroupCompleted = true;
- if (blockStarted && !blockGroupStarted)
- singleBlockGroup = true;
- }
- }
- else if (blockStarted && (c == ' ') && StartOfMultiWordOperator(block))
- {
- //Составной оператор - DEL ACT, DEL OBJ
- block += c;
- }
- else if (blockStarted && (c == ' ') && (qspGetStatCode(block) == (int)QspStatementType.Close) &&
- (line.Length > pos + 3) && line.Substring(pos + 1, 3).Equals("ALL", StringComparison.OrdinalIgnoreCase))
- {
- //CLOSE ALL
- block += c;
- }
- else if (!blockStarted && (c == '*'))
- {
- //Возможно, *PL, *P, *NL
- blockStarted = true;
- blockCompleted = false;
- block += c;
- blockStartPos = pos;
- }
- else if (!blockStarted && (c == '['))
- {
- //Квадратная скобка должна идти вплотную к имени массива
- SubmitError("A square bracket has to be placed just behind the name of the array, with no spaces", lineNum);
- return false;
- }
- else
- {
- //Самостоятельные знаки
- if (c == '(')
- {
- bracketLevel++;
- }
- else if (c == ')')
- {
- if (bracketLevel == 0)
- {
- SubmitError("Redundant bracket \")\"", lineNum);
- return false;
- }
- bracketLevel--;
- }
- bool whiteSpace = c.ToString().IndexOfAny(WhiteSpace) == 0;
- //Особый учет для последовательностей >=, => и т.д.
- bool comparer = pos + 1 < line.Length;
- String cmp = "";
- if (comparer)
- {
- cmp = line.Substring(pos, 2);
- comparer = cmp.Equals("<=") || cmp.Equals(">=") || cmp.Equals("=>") || cmp.Equals("=<") || cmp.Equals("<>") ||
- cmp.Equals("+=") || cmp.Equals("-=");
- }
- if (comparer)
- {
- //<= >= => =< <> += -=
- if (blockStarted)
- {
- appendDelimiter = true;
- delimiterToAppend = cmp;
- }
- else
- {
- blockStarted = true;
- blockStartPos = pos;
- block = cmp;
- }
- blockCompleted = true;
- pos++;
- }
- else if (blockStarted)
- {
- blockCompleted = true;
- if (!whiteSpace)
- {
- appendDelimiter = true;
- delimiterToAppend += c;
- }
- else
- {
- //Обрабатываем END IF, END ACT
- int blockCode = qspGetStatCode(block);
- if (blockCode == (int)QspStatementType.End)
- {
- int nextPos = line.LastIndexOfAny(WhiteSpace, blockStartPos + block.Length) + 1;
- if (nextPos < line.Length)
- {
- int delimPos = line.IndexOfAny(Delimiters, nextPos);
- string nextWord = "";
- if (delimPos == INVALID_INDEX)
- nextWord = line.Substring(nextPos);
- else
- nextWord = line.Substring(nextPos, delimPos - nextPos);
- int nextCode = qspGetStatCode(nextWord);
- if ((nextCode == (int)QspStatementType.If) || (nextCode == (int)QspStatementType.Act))
- {
- pos = nextPos + nextWord.Length - 1;
- }
- }
- }
- }
- }
- else if (!whiteSpace)
- {
- blockStarted = true;
- blockCompleted = true;
- blockStartPos = pos;
- block += c;
- }
- }
- }
- else
- {
- //Просто буквы
- if (!blockStarted)
- {
- blockStarted = true;
- blockCompleted = false;
- blockStartPos = pos;
- }
- block += c;
- }
- }
- //Последний символ в строке
- if (blockStarted && (pos == line.Length - 1))
- {
- blockCompleted = true;
- }
- if (blockCompleted || quotedTextCompleted)
- {
- if (!quotedTextCompleted && (block.Length == 0))
- {
- SubmitError("Internal error of analyzer! Empty block!", lineNum);
- return false;
- }
- debugText += "[" + block + "] ";
- bool skip = false;
- int blockCode = qspGetStatCode(block);
- if (blockCode == (int)QspStatementType.If)
- {
- controlBlock = (int)ControlBlockType.IfCondition;
- debugText += "<IfCondition> ";
- lastIfPos = blockStartPos;
- }
- if (blockCode == (int)QspStatementType.Act)
- {
- controlBlock = (int)ControlBlockType.ActCondition;
- debugText += "<ActCondition> ";
- lastActPos = blockStartPos;
- }
- if (blockCode == (int)QspStatementType.ElseIf)
- {
- if (controlBlock == (int)ControlBlockType.ML_If)
- {
- controlBlock = (int)ControlBlockType.ElseIfCondition;
- debugText += "<ElseIfCondition> ";
- lastIfPos = blockStartPos;
- }
- else
- {
- SubmitError("ELSEIF без IF", lineNum);
- return false;
- }
- }
- if (blockCode == (int)QspStatementType.Else)
- {
- if (controlBlock == (int)ControlBlockType.ML_If)
- {
- if (firstSymbolPos == blockStartPos)
- {
- if ((blockStartPos + block.Length == line.Length) || (line.Substring(blockStartPos + block.Length).Trim(WhiteSpace).Equals(":")))
- {
- controlBlock = (int)ControlBlockType.ML_Else;
-
- ControlStack.Pop();
- ControlLine cline;
- cline.controlBlock = ControlBlockType.ML_Else;
- cline.line = lineNum;
- ControlStack.Push(cline);
- }
- else
- {
- SubmitError("An operator cannot be placed after multiline ELSE", lineNum);
- return false;
- }
- }
- else
- {
- SubmitError("Multiline ELSE should be at the beginning of the line", lineNum);
- return false;
- }
- }
- else
- {
- if (controlBlock == (int)ControlBlockType.SL_Act)
- {
- if (groupInnerCounter > 0)
- {
- if ((ControlStack.Peek().controlBlock == ControlBlockType.SL_If) && (ControlStack.Peek().line == lineNum))
- {
- if (blockGroupStarted)
- {
- blockGroupCompleted = true;
- }
- }
- else
- {
- SubmitError("ELSE without IF", lineNum);
- return false;
- }
- }
- else
- {
- SubmitError("Invalid notation of single line ACT", lineNum);
- return false;
- }
- }
- else if (controlBlock == (int)ControlBlockType.SL_If)
- {
- if (blockGroupStarted)
- {
- blockGroupCompleted = true;
- }
- else if (groupInnerCounter == 0)
- {
- SubmitError("After single line IF has to be any operators before ELSE", lineNum);
- return false;
- }
- }
- else
- {
- SubmitError("ELSE without IF", lineNum);
- return false;
- }
- //Это правильный ELSE
- if (blockStartPos + block.Length < line.Length)
- {
- string restLine = line.Substring(blockStartPos + block.Length);
- if (restLine.Trim(WhiteSpace).StartsWith(":"))
- {
- pos += restLine.IndexOf(':') + 1;
- }
- }
- ControlStack.Pop();
- controlBlock = (int)ControlBlockType.SL_Else;
- groupInnerCounter = 0;
- }
- skip = true;
- }
- if (blockCode == (int)QspStatementType.End)
- {
- if (ControlStack.Count > 0)
- {
- ControlStack.Pop();
- if (ControlStack.Count > 0)
- {
- ControlLine cline = ControlStack.Peek();
- controlBlock = (int)cline.controlBlock;
- }
- else
- {
- controlBlock = (int)ControlBlockType.None;
- }
- }
- else
- {
- SubmitError("Redundant END", lineNum);
- return false;
- }
- skip = true;
- }
- if (!skip)
- {
- if (!blockGroupStarted)
- {
- blockGroupStarted = true;
- groupInnerCounter++;
- if (singleBlockGroup)
- {
- singleBlockGroup = false;
- blockGroupCompleted = true;
- }
- }
- if (quotedTextCompleted)
- {
- blockGroup.Add(quotedText);
- blockInGroupIsText.Add(true);
- quotedTextCompleted = false;
- }
- else
- {
- if ((blockCode == (int)QspStatementType.Unknown) && (block.Length > 1))
- {
- //Обрабатываем попытки "склеить" некоторые последовательности символов
- string first = block.Substring(0, 1);
- if (first.Equals("*"))
- {
- //Если была неудачная попытка прочесть *NL, *P, и т.д., "разделяем" блок на части
- blockGroup.Add(first);
- blockInGroupIsText.Add(false);
- block = block.Substring(1);
- }
- }
- blockGroup.Add(block);
- blockInGroupIsText.Add(false);
- }
- if (appendDelimiter)
- {
- blockGroup.Add(delimiterToAppend);
- blockInGroupIsText.Add(false);
- }
- if (blockGroupStarted && (pos == line.Length - 1))
- {
- blockGroupCompleted = true;
- }
- }
- block = "";
- blockCompleted = false;
- blockStarted = false;
- }
- if (blockGroupCompleted)
- {
- //Разбор аргументов
- if (blockGroup.Count == 0)
- {
- SubmitError("Internal error of the analyzer! Empty block!", lineNum);
- return false;
- }
- if (!CheckBlockGroup(blockGroup, blockInGroupIsText))
- return false;
- blockGroup.Clear();
- blockInGroupIsText.Clear();
- blockGroupStarted = false;
- blockGroupCompleted = false;
- }
- pos++;
- }
-
- //Строка закончилась
- if (bracketLevel>0)
- {
- SubmitError("Redundant bracket \"(\"", lineNum);
- return false;
- }
- if (controlBlock == (int)ControlBlockType.IfCondition)
- {
- SubmitError("IF without \":\"", lineNum);
- return false;
- }
- if (controlBlock == (int)ControlBlockType.ActCondition)
- {
- SubmitError("ACT without \":\"", lineNum);
- return false;
- }
- if ((controlBlock == (int)ControlBlockType.SL_Act) || (controlBlock == (int)ControlBlockType.SL_If) || (controlBlock == (int)ControlBlockType.SL_Else))
- {
- if (groupInnerCounter > 0)
- {
- while ((ControlStack.Count > 0) && (ControlStack.Peek().controlBlock == ControlBlockType.SL_If))
- ControlStack.Pop();
- if (ControlStack.Count > 0)
- {
- ControlLine cline = ControlStack.Peek();
- controlBlock = (int)cline.controlBlock;
- }
- else
- {
- controlBlock = (int)ControlBlockType.None;
- }
- }
- else if (controlBlock == (int)ControlBlockType.SL_Act)
- {
- SubmitError("Invalid notation of single line ACT", lineNum);
- return false;
- }
- else if (controlBlock == (int)ControlBlockType.SL_If)
- {
- SubmitError("Invalid notation of single line IF", lineNum);
- return false;
- }
- else if (controlBlock == (int)ControlBlockType.SL_Else)
- {
- SubmitError("In single line IF has to be any operators after ELSE", lineNum);
- return false;
- }
- }
- //для отладки
- if (line.Length > 0)
- {
- debugText += Environment.NewLine;
- }
-
- if (currentRoot)
- {
- //Вычисляем уровень вложенности(для утилиты форматирования кода)
- int stackSize = ControlStack.Count;
- int level = 0;
- if (stackSize > 0)
- {
- endIndentLevel = stackSize;
- ControlLine cline = ControlStack.Peek();
- int b = (int)cline.controlBlock;
- bool openingLine = cline.line == currentLine;
- if (openingLine && ((b == (int)ControlBlockType.ML_Act) || (b == (int)ControlBlockType.ML_If)))
- {
- level = startIndentLevel;
- }
- else if (openingLine && (b == (int)ControlBlockType.ML_Else))
- {
- level = startIndentLevel - 1;
- }
- else
- {
- level = endIndentLevel;
- }
- }
- location_codeline_level.Add(currentLine, level);
- }
- }
- //Проверка на незакрытые в конце локации многострочные IF и ACT
- if (ControlStack.Count > 0)
- {
- ControlLine cline = ControlStack.Pop();
- if ((cline.controlBlock == ControlBlockType.ML_If) || (cline.controlBlock == ControlBlockType.ML_Else))
- {
- SubmitError("Multi line IF without END", cline.line);
- return false;
- }
- else
- {
- SubmitError("Multi line ACT without END", cline.line);
- return false;
- }
- }
- AddLocationLink(m_name, true, m_start);
- return true;
- }
- bool CheckBlockGroup(List<string> blockGroup, List<bool> blockInGroupIsText)
- {
- //Разбор аргументов для операторов ACT, IF, прочих операторов и функций.
- string pomvarstr1;
- string pomvarstr2;
- bool iifpresent;
- int blockCode = qspGetStatCode(blockGroup.ToArray()[0]);
- if (blockInGroupIsText[0])
- blockCode = (int)QspStatementType.Unknown;
- bool isSetOp = blockCode == (int)QspStatementType.Set;
- if ((blockCode == (int)QspStatementType.Unknown) || isSetOp)
- {
- //Это присваивание?
- int setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "=");
- if (setpos == INVALID_INDEX)
- setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "+=");
- if (setpos == INVALID_INDEX)
- setpos = FindInTopBracketLevel(blockGroup, blockInGroupIsText, "-=");
- if (isSetOp && (setpos == INVALID_INDEX))
- {
- SubmitError("Not found the char \"=\"", currentLine);
- return false;
- }
- if (setpos != INVALID_INDEX)
- {
- //Присваивание
- if ((setpos == 0) || (isSetOp && (setpos == 1)))
- {
- SubmitError("The name of a variable before the character \"=\" is not specified!", currentLine);
- return false;
- }
- int last = blockGroup.Count - 1;
- if (setpos==last)
- {
- SubmitError("It should be a value after char \"=\"", currentLine);
- return false;
- }
- //Проверяем левую часть
- int start = 0;
- if (isSetOp)
- start = 1;
- int count = setpos - start;
- List<string> args = new List<string>();
- List<bool> types = new List<bool>();
- args = blockGroup.GetRange(start, count);
- types = blockInGroupIsText.GetRange(start, count);
- if (!CheckLeftAssign(args, types))
- return false;
- string assignedVarName = args[0];
- //Проверяем правую часть
- start = setpos + 1;
- count = last - start + 1;
- args = blockGroup.GetRange(start, count);
- types = blockInGroupIsText.GetRange(start, count);
- if (!CheckExpression(args, types))
- return false;
- //Засчитываем присваивание некоторым переменным как обращение к локации
- if ((count == 1) && types[0] && ListContainsIgnoreCase(callerVariables, assignedVarName))
- {
- AddLocationLink(args[0], false, true);
- }
- }
- else
- {
- //Если оператор неизвестен, пытаемся разобрать выражение
- if (!CheckExpression(blockGroup, blockInGroupIsText))
- return false;
- //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
- if ((blockGroup.Count >= 1) && (blockInGroupIsText[0]))
- {
- pomvarstr1 = "";
- pomvarstr2 = "";
- iifpresent = false;
- for (int ibc = 0; ibc < blockGroup.Count; ibc++)
- {
- if (blockGroup[Math.Min(ibc + 1, blockGroup.Count-1)] != "iif")
- {
- pomvarstr1 = pomvarstr1 + blockGroup[ibc];
- pomvarstr2 = pomvarstr2 + blockGroup[ibc];
- }
- else
- {
- iifpresent = true;
- while (blockGroup[ibc] != ",")
- {
- ibc++;
- }
- ibc++;
- pomvarstr1 = pomvarstr1 + blockGroup[ibc];
- ibc++;
- ibc++;
- pomvarstr2 = pomvarstr2 + blockGroup[ibc];
- ibc++;
- ibc++;
- }
- }
- ParseExecInOutputText(pomvarstr1);
- if (iifpresent)
- ParseExecInOutputText(pomvarstr2);
- }
- }
- }
- else if ((blockCode == (int)QspStatementType.If) || (blockCode == (int)QspStatementType.ElseIf))
- {
- int start = 1;
- int count = blockGroup.Count - 1;
- if (count > 0)
- {
- List<string> args = blockGroup.GetRange(start, count);
- List<bool> types = blockInGroupIsText.GetRange(start, count);
- if (!CheckExpression(args, types))
- return false;
- }
- else
- {
- if (blockCode == (int)QspStatementType.If)
- {
- SubmitError("Operator IF without condition", currentLine);
- }
- else
- {
- SubmitError("Operator ELSEIF without condition", currentLine);
- }
- return false;
- }
- }
- else
- {
- //Если оператор известен, проверяем его аргументы.
- int count = blockGroup.Count - 1;
- List<string> args = new List<string>();
- List<bool> types = new List<bool>();
- if (count > 0)
- {
- args = blockGroup.GetRange(1, count);
- types = blockInGroupIsText.GetRange(1, count);
- }
- if (!CheckStatementArgs(blockCode, args, types))
- return false;
- }
- //Проверяем подвыражения вида <<$var>> в любых строках
- for (int i = 0; i < blockGroup.Count; i++)
- {
- if (blockInGroupIsText[i])
- {
- if (!ParseSubExpressions(blockGroup[i]))
- return false;
- }
- }
- return true;
- }
- bool CheckStatementArgs(int code, List<string> argsSrc, List<bool> typesSrc)
- {
- int count = argsSrc.Count;
- List<string> args = new List<string>();
- List<bool> types = new List<bool>();
- if (count > 0)
- {
- if ((count > 1) && argsSrc.ToArray()[0].Equals("(") && !typesSrc.ToArray()[0] &&
- argsSrc.ToArray()[count - 1].Equals(")") && !typesSrc.ToArray()[count - 1])
- {
- //Игнорируем одну пару скобок по краям
- args = argsSrc.GetRange(1, count - 2);
- types = typesSrc.GetRange(1, count - 2);
- }
- else
- {
- args = argsSrc.GetRange(0, count);
- types = typesSrc.GetRange(0, count);
- }
- }
- count = args.Count;
- if ((count >= 1) && types[0])
- {
- //Отмечаем в списке явные ссылки на локации
- if ((code == (int)QspStatementType.GoSub) || (code == (int)QspStatementType.GoTo) ||
- (code == (int)QspStatementType.XGoTo))
- {
- AddLocationLink(args[0], false, true);
- }
- //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
- else if ((code == (int)QspStatementType.P) || (code == (int)QspStatementType.PL) ||
- (code == (int)QspStatementType.NL) || (code == (int)QspStatementType.MP) ||
- (code == (int)QspStatementType.MPL) || (code == (int)QspStatementType.MNL))
- {
- ParseExecInOutputText(args[0]);
- }
- //Отмечаем в списке добавленные предметы
- else if (code == (int)QspStatementType.AddObj)
- {
- AddObj(args[0], true, false);
- }
- //Отмечаем в списке удаленные предметы
- else if (code == (int)QspStatementType.DelObj)
- {
- AddObj(args[0], false, true);
- }
- //Отмечаем в списке добавленные действия
- else if (code == (int)QspStatementType.Act)
- {
- AddAct(args[0], true, false);
- }
- //Отмечаем в списке удаленные действия
- else if (code == (int)QspStatementType.DelAct)
- {
- AddAct(args[0], false, true);
- }
- }
- int minArgCount = qspStats[code].MinArgsCount;
- int maxArgCount = qspStats[code].MaxArgsCount;
- int argCount = 0;
- int curIndex = 0;
- List<string> expr = new List<string>();
- if (count > 0)
- {
- while (true)
- {
- if (argCount == maxArgCount)
- {
- SubmitError("Too many arguments for the operator", currentLine);
- return false;
- }
- int index = FindInTopBracketLevel(args, types, ",", curIndex);
- if (index != INVALID_INDEX)
- {
- if (index > curIndex)
- {
- if (!CheckExpression(args.GetRange(curIndex, index - curIndex), types.GetRange(curIndex, index - curIndex)))
- return false;
- }
- else
- {
- SubmitError("Argument can not be empty", currentLine);
- return false;
- }
- }
- else
- {
- if (!CheckExpression(args.GetRange(curIndex, count - curIndex), types.GetRange(curIndex, count - curIndex)))
- return false;
- }
- argCount++;
- if (index == INVALID_INDEX)
- break;
- curIndex = index + 1;
- if (curIndex == count)
- {
- SubmitError("Argument can not be empty", currentLine);
- return false;
- }
- }
- }
- if (argCount < minArgCount)
- {
- SubmitError("The operator requires more arguments", currentLine);
- return false;
- }
- return true;
- }
- bool CheckExpression(List<string> args, List<bool> types)
- {
- //Проверка выражения
- int[] opStack = new int[QSP_STACKSIZE];
- int[] argStack = new int[QSP_STACKSIZE];
- bool waitForOperator = false;
- int opCode, itemsCount = 0, opSp = -1, argSp = -1;
- if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Start))
- return false;
- int argIndex = 0;
- while (argIndex <= args.Count)
- {
- String s = "";
- if (argIndex < args.Count)
- s = args[argIndex];
- if (waitForOperator)
- {
- opCode = qspGetFunctionCode(s, false);
- String nextArg = "";
- bool nextArgIsString = false;
- bool hasNextArg = argIndex + 1 < args.Count;
- if (hasNextArg)
- {
- nextArg = args[argIndex + 1];
- nextArgIsString = types[argIndex + 1];
- }
- if (opCode == (int)QspFunctionType.Unknown || opCode >= (int)QspFunctionType.First_Function)
- {
- SubmitError("Unknown action in the expression", currentLine);
- break;
- }
- if (((opCode == (int)QspFunctionType.And) || (opCode == (int)QspFunctionType.Or) || (opCode == (int)QspFunctionType.Mod)) &&
- !(hasNextArg && (nextArgIsString || nextArg.Equals("(") || (nextArg.IndexOfAny(Delimiters) == INVALID_INDEX)))
- )
- {
- SubmitError("Syntax error", currentLine);
- break;
- }
- bool bError = false;
- while (qspOps[opCode].Priority <= qspOps[opStack[opSp]].Priority && qspOps[opStack[opSp]].Priority != 127)
- {
- if (opStack[opSp] >= (int)QspFunctionType.First_Function) ++argStack[argSp];
- if (!qspAppendToCompiled(ref itemsCount))
- {
- bError = true;
- break;
- }
- if (--opSp < 0 || --argSp < 0)
- {
- SubmitError("Syntax error", currentLine);
- bError = true;
- break;
- }
- }
- if (bError)
- break;
- switch (opCode)
- {
- case (int)QspFunctionType.End:
- if (opSp > 0)
- {
- SubmitError("Closing bracket not found", currentLine);
- bError = true;
- break;
- }
- return itemsCount > 0;
- case (int)QspFunctionType.CloseBracket:
- if (opStack[opSp] != (int)QspFunctionType.OpenBracket)
- {
- SubmitError("Opening bracket not found", currentLine);
- bError = true;
- break;
- }
- opCode = opStack[--opSp];
- if (opCode >= (int)QspFunctionType.First_Function)
- {
- if (argStack[argSp] + 1 < qspOps[opCode].MinArgsCount || argStack[argSp] + 1 > qspOps[opCode].MaxArgsCount)
- {
- SubmitError("Invalid number of arguments", currentLine);
- bError = true;
- }
- }
- else
- --argSp;
- break;
- case (int)QspFunctionType.Comma:
- if ((opSp > 0) && opStack[opSp - 1] >= (int)QspFunctionType.First_Function)
- {
- if (++argStack[argSp] > qspOps[opStack[opSp - 1]].MaxArgsCount)
- {
- SubmitError("Invalid number of arguments", currentLine);
- bError = true;
- break;
- }
- }
- else
- {
- if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Comma))
- {
- bError = true;
- break;
- }
- }
- waitForOperator = false;
- break;
- default:
- if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
- {
- bError = true;
- break;
- }
- waitForOperator = false;
- break;
- }
- if (bError)
- break;
- }
- else
- {
- if ((argIndex < args.Count) && !types[argIndex] && IsNumber(s))
- {
- if (opStack[opSp] == (int)QspFunctionType.Minus)
- {
- --opSp;
- --argSp;
- }
- if (!qspAppendToCompiled(ref itemsCount))
- break;
- waitForOperator = true;
- }
- // 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
- // I do not assure that I did it in a proper place, but it seems that it works.
- else if ((opStack[1] == (int)QspFunctionType.Func) && (argIndex == 2))
- {
- AddLocationLink(s, false, true);
- }
- else if ((opStack[1] == (int)QspFunctionType.Func) && (argIndex == 3) && (s == ","))
- {
- }
- else if ((argIndex < args.Count) && types[argIndex])
- {
- if (!qspAppendToCompiled(ref itemsCount))
- break;
- waitForOperator = true;
- }
- else if (s.Equals("+"))
- {
- }
- else if (s.Equals("-"))
- {
- if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.Minus))
- break;
- }
- else if (s.Equals("("))
- {
- if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.OpenBracket))
- break;
- }
- else if (s.Equals(")"))
- {
- opCode = opStack[opSp];
- if (opCode != (int)QspFunctionType.OpenBracket)
- {
- if (opCode >= (int)QspFunctionType.First_Function)
- SubmitError("Invalid number of arguments", currentLine);
- else
- SubmitError("Syntax error", currentLine);
- break;
- }
- opCode = opStack[--opSp];
- if (opCode < (int)QspFunctionType.First_Function)
- {
- SubmitError("Syntax error", currentLine);
- break;
- }
- if (qspOps[opCode].MinArgsCount > argSp)
- {
- SubmitError("Invalid number of arguments", currentLine);
- break;
- }
- if (!qspAppendToCompiled(ref itemsCount))
- break;
- --opSp;
- --argSp;
- waitForOperator = true;
- }
- else if ((argIndex < args.Count) && s.IndexOfAny(Delimiters) != 0)
- {
- if (s.IndexOfAny(Delimiters) != INVALID_INDEX)
- {
- SubmitError("Internal error of the analyzer: Invalid characters in the variable name", currentLine);
- break;
- }
- opCode = qspGetFunctionCode(s, true);
- if (opCode >= (int)QspFunctionType.First_Function)
- {
- if ((args.Count - argIndex > 1) && (args[argIndex + 1].Equals("(") && !types[argIndex + 1]))
- {
- if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
- break;
- if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, (int)QspFunctionType.OpenBracket))
- break;
- argIndex++;
- --argSp;
- }
- else if (qspOps[opCode].MinArgsCount < 2)
- {
- if (qspOps[opCode].MinArgsCount > 0)
- {
- if (!qspCompileExprPushOpCode(ref opStack, ref opSp, ref argStack, ref argSp, opCode))
- break;
- }
- else
- {
- if (!qspAppendToCompiled(ref itemsCount))
- break;
- waitForOperator = true;
- }
- }
- else
- {
- SubmitError("Brackets not found", currentLine);
- break;
- }
- }
- else
- {
- int optArgsCount = 0;
- //Проверяем выражение(индекс массива)
- if ((args.Count - argIndex > 1) && (args[argIndex + 1].Equals("[") && !types[argIndex + 1]))
- {
- int optIndex = argIndex + 2;
- int level = 1;
- bool bFound = false;
- while (optIndex < args.Count)
- {
- if (args[optIndex].Equals("[") && !types[optIndex])
- {
- level++;
- }
- else if (args[optIndex].Equals("]") && !types[optIndex])
- {
- level--;
- if (level == 0)
- {
- bFound = true;
- break;
- }
- }
- optIndex++;
- }
- if (level > 0)
- {
- SubmitError("Unclosed parenthesis \"[\"", currentLine);
- break;
- }
- if (bFound)
- optArgsCount = optIndex - argIndex;
- }
- List<string> subArgs = args.GetRange(argIndex, optArgsCount + 1);
- List<bool> subTypes = types.GetRange(argIndex, optArgsCount + 1);
- if (!CheckVariable(subArgs, subTypes, false))
- break;
-
- argIndex += optArgsCount;
- if (!qspAppendToCompiled(ref itemsCount))
- break;
- waitForOperator = true;
- }
- }
- else
- {
- if (opStack[opSp] >= (int)QspFunctionType.First_Function)
- SubmitError("Invalid number of arguments", currentLine);
- else
- SubmitError("Syntax error", currentLine);
- break;
- }
- }
- argIndex++;
- }
- return false;
- }
- bool CheckVariable(List<string> args, List<bool> types, bool assignment)
- {
- //Проверка имени переменной
- if ((args.Count == 0) || (args[0].Length == 0) || types[0])
- {
- SubmitError("Internal error of the analyzer: empty name of variable!", currentLine);
- return false;
- }
- string name = args[0];
- int code1 = qspGetStatCode(name);
- int code2 = qspGetFunctionCode(name, true);
- if ((code1 != (int)QspStatementType.Unknown) || (code2 != (int)QspFunctionType.Unknown))
- {
- SubmitError("QSP Keyword \"" + name + "\" cannot be used as a variable name", currentLine);
- return false;
- }
- //Проверяем имя переменной на валидность
- //В имени переменной разрешены все символы, кроме DELIMS и цифры в начале имени
- //Перед именем переменной может находиться префикс "$"
- string checkName = name;
- if (checkName.StartsWith("$"))
- checkName = checkName.Substring(1);
- // $ =
- if (checkName.Length == 0)
- {
- SubmitError("Invalid variable name \"" + name + "\"", currentLine);
- return false;
- }
- // 1asd =
- if (checkName.Substring(0, 1).IndexOfAny(Digits) != INVALID_INDEX)
- {
- SubmitError("Variable name \"" + name + "\" cannot start with a digit", currentLine);
- return false;
- }
- // /asd =
- if (checkName.IndexOfAny(Delimiters) != INVALID_INDEX)
- {
- SubmitError("Invalid symbols in the name of the variable \"" + name + "\"", currentLine);
- return false;
- }
- //Проверяем переменную на "смешанные раскладки"
- if ((checkName.IndexOfAny(LatinLetters) != INVALID_INDEX) && (checkName.IndexOfAny(RussianLetters) != INVALID_INDEX))
- {
- SubmitWarning("English and Russian symbols are used simultaneously in the name of varible \"" + name + "\" , possibly a typo", currentLine);
- }
- //Проверяем выражение(индекс массива)
- if (args.Count > 1)
- {
- if (args.Count > 2 && args[1].Equals("[") && !types[1] &&
- args[args.Count - 1].Equals("]") && !types[args.Count - 1])
- {
- int start = 2;
- int count = args.Count - 3;
- if (count > 0)
- {
- List<string> argsCut = args.GetRange(start, count);
- List<bool> typesCut = types.GetRange(start, count);
- if (!CheckExpression(argsCut, typesCut))
- return false;
- }
- }
- else
- {
- SubmitError("Invalid expression", currentLine);
- return false;
- }
- }
- //Сохраняем имя переменной в глобальном списке
- if (!assignment)
- {
- bool usedBySystem = ListContainsIgnoreCase(systemVariables, name);
- AddVar(name, usedBySystem, true);
- }
- return true;
- }
-
- bool CheckLeftAssign(List<string> args, List<bool> types)
- {
- //Проверка имени переменной(слева от знака "=" в операции присваивания)
- if ((args.Count == 0) || (args[0].Length == 0) || types[0])
- {
- //Текстовая строка
- SubmitError("Name of the variable should be before char \"=\" in the assignment operation", currentLine);
- return false;
- }
- if (!CheckVariable(args, types, true))
- return false;
- //Сохраняем имя переменной в глобальном списке
- bool usedBySystem = ListContainsIgnoreCase(systemVariables, args[0]);
- AddVar(args[0], true, usedBySystem);
- return true;
- }
- int FindInTopBracketLevel(List<string> args, List<bool> types, string what)
- {
- return FindInTopBracketLevel(args, types, what, 0);
- }
- int FindInTopBracketLevel(List<string> args, List<bool> types, string what, int startIndex)
- {
- //Ищем знак "=" или запятую вне скобок
- int bracketLevel = 0;
- for (int i = startIndex; i < args.Count; i++)
- {
- if (types[i])
- continue;
- string block = args[i];
- if (block.Equals("("))
- {
- bracketLevel++;
- }
- else if (block.Equals(")"))
- {
- bracketLevel--;
- }
- else if (block.Equals(what) && (bracketLevel == 0))
- {
- return i;
- }
- }
- return INVALID_INDEX;
- }
- void ParseExecInOutputText(string text)
- {
- //Разбираем код в ссылках <a href="EXEC:GOTO 'loc1'">
- int pos = 0;
- //Строим "карту" подвыражений.
- //Если подвыражения в строке содержат ошибки, то разбирать теги нет смысла.
- List<int> subExpMap = new List<int>();
- if (!ParseSubExpressions(text, ref subExpMap))
- return;
- int subExpSkipped = 0;
- while (pos < text.Length)
- {
- pos = text.IndexOf("<a", pos);
- if (pos == INVALID_INDEX)
- break;
- if (subExpMap.Count / 2 > subExpSkipped)
- {
- int subExpStartPos = subExpMap[subExpSkipped * 2];
- int subExpEndPos = subExpMap[subExpSkipped * 2 + 1];
- if (subExpStartPos == pos)
- {
- //Пропускаем подвыражения вне тегов
- subExpSkipped++;
- pos = subExpEndPos + 1;
- continue;
- }
- }
- //Разбираем содержимое угловых скобок
- //Внутри HTML-тега кавычки экранируются не через дублирование, как в QSP, а через "\",
- //причем экранирование требуется только внутри окавыченной строки.
- List<string> blockGroup = new List<string>();
- List<bool> blockInGroupIsText = new List<bool>();
- int firstBlockPosition = INVALID_INDEX;
- string quotedText = "";
- string block = "";
- bool tagClosed = false;
- bool quotedTextCompleted = false;
- bool blockCompleted = false;
- pos++;
- int startPos = pos;
- if ((pos < text.Length) && (text[pos] == '/'))
- startPos++;
- int tagQuote = (int)QuoteType.None;
- while (!tagClosed && (pos < text.Length))
- {
- if (subExpMap.Count / 2 > subExpSkipped)
- {
- int subExpStartPos = subExpMap[subExpSkipped * 2];
- int subExpEndPos = subExpMap[subExpSkipped * 2 + 1];
- if (subExpStartPos == pos)
- {
- //Пропускаем подвыражения вне тегов
- subExpSkipped++;
- string subExpText = text.Substring(pos, subExpEndPos - pos + 1);
- if (tagQuote == (int)QuoteType.None)
- block += subExpText;
- else
- quotedText += subExpText;
- pos = subExpEndPos + 1;
- continue;
- }
- }
- char c2 = text[pos];
- if (tagQuote != (int)QuoteType.None)
- {
- //Апостроф либо кавычка
- if (((tagQuote == (int)QuoteType.Single) && (c2 == '\'')) ||
- ((tagQuote == (int)QuoteType.Double) && (c2 == '"')))
- {
- if ((pos - 1 > 0) && (text[pos - 1] == '\\'))
- {
- //Экранированный апостроф либо кавычка
- if (!quotedTextCompleted)
- quotedText = quotedText.Substring(0, quotedText.Length - 1) + c2;
- }
- else
- {
- tagQuote = (int)QuoteType.None;
- quotedTextCompleted = true;
- }
- }
- else if (!quotedTextCompleted)
- {
- quotedText += c2;
- }
- }
- else if (c2 == '>')
- {
- tagClosed = true;
- }
- else if ((block.Length == 0) && (c2 == '\''))
- {
- tagQuote = (int)QuoteType.Single;
- if (text[pos + 1] == '\'')
- {
- pos++;
- }
- }
- else if ((block.Length == 0) && (c2 == '"'))
- {
- tagQuote = (int)QuoteType.Double;
- }
- else if (c2.ToString().IndexOfAny(WhiteSpace) == 0)
- {
- if (block.Length > 0)
- {
- blockCompleted = true;
- }
- }
- else if (c2 == '=')
- {
- if (block.Length > 0)
- {
- blockGroup.Add(block);
- blockInGroupIsText.Add(false);
- }
- block = "=";
- blockCompleted = true;
- }
- else
- {
- if (firstBlockPosition == INVALID_INDEX)
- {
- firstBlockPosition = pos - startPos;
- }
- block += c2;
- }
- if (tagClosed)
- {
- if (block.Length > 0)
- blockCompleted = true;
- }
- if (blockCompleted)
- {
- blockGroup.Add(block);
- blockInGroupIsText.Add(false);
- blockCompleted = false;
- block = "";
- }
- if (quotedTextCompleted)
- {
- blockGroup.Add(quotedText);
- blockInGroupIsText.Add(true);
- quotedTextCompleted = false;
- quotedText = "";
- }
- pos++;
- }
-
- if (tagQuote == (int)QuoteType.Single)
- {
- SubmitWarning("Unclosed apostrophe inside the tag", currentLine);
- break;
- }
- else if (tagQuote == (int)QuoteType.Double)
- {
- SubmitWarning("Unclosed quote inside the tag", currentLine);
- break;
- }
- if (!tagClosed)
- {
- SubmitWarning("Unclosed tag",currentLine);
- break;
- }
- if (firstBlockPosition > 0)
- {
- SubmitWarning("The name of the tag should follow immediately after the opening angle bracket, without spaces", currentLine);
- break;
- }
- //Ищем HREF в атрибутах тега A
- int hrefIndex = INVALID_INDEX;
- if ((blockGroup.Count > 3) && (blockGroup[0].Equals("A", StringComparison.OrdinalIgnoreCase)) && !blockInGroupIsText[0])
- {
- for (int i = 1; i + 2 < blockGroup.Count; i++)
- {
- if (blockGroup[i].Equals("HREF", StringComparison.OrdinalIgnoreCase) && !blockInGroupIsText[i] &&
- blockGroup[i + 1].Equals("=") && !blockInGroupIsText[i + 1])
- {
- hrefIndex = i + 2;
- }
- }
- }
- if (hrefIndex != INVALID_INDEX)
- {
- string hrefText = blockGroup[hrefIndex];
- int execKeywordLength = "EXEC:".Length;
- if (hrefText.StartsWith("EXEC:", StringComparison.OrdinalIgnoreCase) && (hrefText.Length > execKeywordLength))
- {
- string execText = hrefText.Substring(execKeywordLength);
- List<int> subExpMapExec = new List<int>();
- ParseSubExpressions(execText, ref subExpMapExec);
- if (subExpMapExec.Count == 0)
- {
- //В EXEC не разбираем код с подвыражениями, это невозможно без интерпретации
- List<string> tagLines = new List<string>(execText.Split('\n'));
- bool wasRoot = currentRoot;
- currentRoot = false;
- ParseLocation(tagLines, currentRoot);
- currentRoot = wasRoot;
- }
- }
- }
- }
- }
- bool ParseSubExpressions(string text)
- {
- List<int> dummy = null;
- return ParseSubExpressions(text, ref dummy);
- }
- bool ParseSubExpressions(string text, ref List<int> subExpMap)
- {
- bool quiet = subExpMap != null;
- //Разбираем подвыражения - <<$var>>
- if (quiet)
- subExpMap.Clear();
- int pos = 0;
- bool valid = true;
- while (valid && pos < text.Length)
- {
- pos = text.IndexOf("<<", pos);
- if (pos == INVALID_INDEX)
- break;
- if (quiet)
- subExpMap.Add(pos);
- //Разбираем содержимое двойных угловых скобок
- string subText = "";
- bool subClosed = false;
- pos += 2;
- int subQuote = (int)QuoteType.None;
- int curlyLevel = 0;
- while (pos < text.Length)
- {
- char c2 = text[pos];
- if (subQuote == (int)QuoteType.None)
- {
- if ((c2 == '>') && (pos + 1 < text.Length) && (text[pos + 1] == '>') && (curlyLevel == 0))
- {
- subClosed = true;
- break;
- }
- else if (c2 == '\'')
- {
- subQuote = (int)QuoteType.Single;
- }
- else if (c2 == '"')
- {
- subQuote = (int)QuoteType.Double;
- }
- else if (c2 == '{')
- {
- curlyLevel++;
- }
- else if (c2 == '}')
- {
- curlyLevel--;
- }
- }
- else if (((subQuote == (int)QuoteType.Single) && (c2 == '\'')) ||
- ((subQuote == (int)QuoteType.Double) && (c2 == '"')))
- {
- //Апостроф или кавычка
- if ((pos + 1 < text.Length) && (
- ((subQuote == (int)QuoteType.Single) && (text[pos + 1] == '\'')) ||
- ((subQuote == (int)QuoteType.Double) && (text[pos + 1] == '"'))))
- {
- //Экранированный апостроф либо кавычка
- }
- else
- {
- subQuote = (int)QuoteType.None;
- }
- }
- subText += c2;
- pos++;
- }
- if (quiet)
- {
- if (subClosed)
- subExpMap.Add(pos + 1);
- else
- subExpMap.Add(pos - 1);
- }
- if (subQuote == (int)QuoteType.Single)
- {
- if (!quiet)
- SubmitError("Unclosed apostrophe in a subexpression", currentLine);
- valid = false;
- break;
- }
- else if (subQuote == (int)QuoteType.Double)
- {
- if (!quiet)
- SubmitError("Unclosed quote in a subexpression", currentLine);
- valid = false;
- break;
- }
- else if (curlyLevel != 0)
- {
- if (!quiet)
- SubmitError("Unclosed curly bracket in a subexpression", currentLine);
- valid = false;
- break;
- }
- if (!subClosed)
- {
- if (!quiet)
- SubmitError("Unclosed subexpression", currentLine);
- valid = false;
- break;
- }
- if (subText.Trim(WhiteSpace).Length == 0)
- {
- if (!quiet)
- SubmitError("Empty subexpression", currentLine);
- valid = false;
- break;
- }
- if (!quiet)
- {
- //Парсим подвыражение как исполняемый код.
- //Для того, чтобы строка считалась именно выражением, добавляем ''+ в начало
- subText = "''+" + subText;
- List<string> subLines = new List<string>(subText.Split('\n'));
- bool wasRoot = currentRoot;
- currentRoot = false;
- valid = ParseLocation(subLines, currentRoot);
- currentRoot = wasRoot;
- }
- }
- return valid;
- }
- }
- public class QSPGameCode : Common
- {
- Hashtable m_LocationsByName;
- List<Location> m_LocationsByOrder;
- Location m_lastLocation;
- public QSPGameCode()
- {
- m_LocationsByName = new Hashtable();
- m_LocationsByOrder = new List<Location>();
- m_lastLocation = null;
- }
- public bool ParseGame(string fileName, object sender, DoWorkEventArgs e)
- {
- int totalLines = 0;
- StreamReader rTl = new StreamReader(fileName);
- while (rTl.ReadLine() != null) { totalLines++; };
- m_LocationsByName.Clear();
- m_LocationsByOrder.Clear();
- ClearErrors();
- m_lastLocation = null;
- currentLocation = "";
- vars = new List<QspVariable>();
- locationLinks = new List<QspLocationLink>();
- objects = new List<QspObj>();
- acts = new List<QspAct>();
- StreamReader fi = null;
- if (!OpenStreamForReading(ref fi, fileName))
- {
- return false;
- }
- string s;
- int line_counter = 0;
- List<string> locationCode = new List<string>();
- bool inside = false;
- while ((s = fi.ReadLine()) != null)
- {
- line_counter++;
- string trimmed = s.Trim(WhiteSpace);
- if ((trimmed.Length > 0) && (trimmed[0] == '#'))
- {
- //имя локации
- string locName = trimmed.Substring(1).Trim(WhiteSpace);
- if (!AddLocation(locName, line_counter))
- {
- fi.Close();
- rTl.Close();
- return false;
- }
- currentLocation = locName;
- inside = true;
- }
- else if ((trimmed.Length > 38) && trimmed.StartsWith("--- ") && trimmed.EndsWith(" ---------------------------------"))
- {
- inside = false;
- Location lastLoc = GetLastLocation();
- if (lastLoc != null)
- {
- lastLoc.ParseLocation(locationCode, true);
- locationCode.Clear();
- currentLocation = "";
- }
- }
- else
- {
- if (inside && GetLastLocation() != null)
- locationCode.Add(s);
- }
- (sender as BackgroundWorker).ReportProgress(Convert.ToInt32(((double)line_counter/(double)totalLines) * 100));
- if ((sender as BackgroundWorker).CancellationPending)
- {
- e.Cancel = true;
- return true;
- }
- }
- fi.Close();
- rTl.Close();
- return true;
- }
- public bool AddLocation(string name, int line)
- {
- if (name.Length <= 0)
- {
- SubmitError("Empty name of location", line);
- return false;
- }
- if (m_LocationsByName.ContainsKey(name))
- {
- SubmitError("Location named " + name + " exist already", line);
- return false;
- }
- Location newLoc = new Location(this, name, line, m_LocationsByOrder.Count == 0);
- m_LocationsByName.Add(name, newLoc);
- m_LocationsByOrder.Add(newLoc);
- m_lastLocation = newLoc;
- return true;
- }
- public Location GetLastLocation()
- {
- return m_lastLocation;
- }
- public Hashtable GetLocationsByName()
- {
- return m_LocationsByName;
- }
- public Location GetLocation(string locationName)
- {
- Location loc = (Location)m_LocationsByName[locationName];
- return loc;
- }
- public bool Beautify(string fileName)
- {
- //Причесываем код - добавляем пробелов
- StreamWriter fo = null;
- if (!OpenStreamForWriting(ref fo, fileName))
- return false;
- for (int i = 0; i < m_LocationsByOrder.Count; i++)
- {
- Location loc = (Location)m_LocationsByOrder[i];
- fo.WriteLine("# " + loc.GetName());
- for (int j = 0; j < loc.GetCodeLinesCount(); j++)
- {
- string text = "";
- int level = INVALID_INDEX;
- loc.GetCodeLine(j, ref text, ref level);
- if (level != INVALID_INDEX)
- {
- text = new string(' ', level * 4) + text.TrimStart(WhiteSpace);
- }
- fo.WriteLine(text);
- }
- fo.WriteLine("--- " + loc.GetName() + " ---------------------------------");
- fo.WriteLine();
- }
- fo.Close();
- return true;
- }
- }
- }
|