/// <summary> /// Consoleの文字表示用。字句解析や構文解析に使ってはならない /// </summary> public static int SkipAllSpace(StringStream st) { int count = 0; while (true) { switch (st.Current) { case ' ': case '\t': case ' ': count++; st.ShiftNext(); continue; } return(count); } }
/// <summary> /// TIMES第二引数のみが使用する。 /// Convertクラスが発行する例外をそのまま投げるので適切に処理すること。 /// </summary> /// <param name="st"></param> /// <returns></returns> public static double ReadDouble(StringStream st) { var start = st.CurrentPosition; //大雑把に読み込んでエラー処理はConvertクラスに任せる。 //仮数小数部 if (st.Current == '-' || st.Current == '+') { st.ShiftNext(); } while (!st.EOS) { //仮数部 var c = st.Current; if (char.IsDigit(c) || c == '.') { st.ShiftNext(); continue; } break; } if (st.Current == 'e' || st.Current == 'E') { st.ShiftNext(); if (st.Current == '-') { st.ShiftNext(); } while (!st.EOS) { //指数部 var c = st.Current; if (char.IsDigit(c) || c == '.') { st.ShiftNext(); continue; } break; } } return(Convert.ToDouble(st.Substring(start, st.CurrentPosition - start))); }
/// <summary> /// ボタンの核になるかどうか。とりあえずは整数のみ。 /// try-catchを利用するので少し重い。 /// </summary> /// <param name="str"></param> /// <param name="input"></param> /// <returns></returns> private static bool isButtonCore(string str, ref long input) { if((str == null)||(str.Length < 3)||(str[0] != '[')||(str[str.Length-1] != ']')) return false; if (!isNumericWord(str)) return false; string buttonStr = str.Substring(1, str.Length - 2); StringStream stInt = new StringStream(buttonStr); LexicalAnalyzer.SkipAllSpace(stInt); try { input = LexicalAnalyzer.ReadInt64(stInt, false); } catch { return false; } return true; }
/// <summary> /// 字句解析・構文解析用。ホワイトスペースの他、コメントも飛ばす。 /// </summary> public static int SkipWhiteSpace(StringStream st) { int count = 0; while (true) { switch (st.Current) { case ' ': case '\t': count++; st.ShiftNext(); continue; case ' ': if (!Config.SystemAllowFullSpace) { return(count); } goto case ' '; case ';': if (st.CurrentEqualTo(";#;") && Program.DebugMode) { st.Jump(3); continue; } else if (st.CurrentEqualTo(";!;")) { st.Jump(3); continue; } st.Seek(0, System.IO.SeekOrigin.End); return(count); } return(count); } }
public string CheckEscape(string str) { StringStream st = new StringStream(str); StringBuilder buffer = new StringBuilder(); while (!st.EOS) { //エスケープ文字の使用 if (st.Current == '\\') { st.ShiftNext(); switch (st.Current) { case '\\': buffer.Append('\\'); buffer.Append('\\'); break; case '{': case '}': case '%': case '@': buffer.Append('\\'); buffer.Append(st.Current); break; default: buffer.Append("\\\\"); buffer.Append(st.Current); break; } st.ShiftNext(); continue; } buffer.Append(st.Current); st.ShiftNext(); } return buffer.ToString(); }
/// <summary> /// 失敗したらCodeEE。OperatorManagerには頼らない /// "="の時、OperatorCode.Assignmentを返す。"=="の時はEqual /// </summary> /// <param name="st"></param> /// <returns></returns> public static OperatorCode ReadAssignmentOperator(StringStream st) { OperatorCode ret = OperatorCode.NULL; char cur = st.Current; st.ShiftNext(); char next = st.Current; switch (cur) { case '+': if (next == '+') { ret = OperatorCode.Increment; } else if (next == '=') { ret = OperatorCode.Plus; } break; case '-': if (next == '-') { ret = OperatorCode.Decrement; } else if (next == '=') { ret = OperatorCode.Minus; } break; case '*': if (next == '=') { ret = OperatorCode.Mult; } break; case '/': if (next == '=') { ret = OperatorCode.Div; } break; case '%': if (next == '=') { ret = OperatorCode.Mod; } break; case '=': if (next == '=') { ret = OperatorCode.Equal; break; } return(OperatorCode.Assignment); case '\'': if (next == '=') { ret = OperatorCode.AssignmentStr; break; } throw new CodeEE("\"\'\"は代入演算子として認識できません"); case '<': if (next == '<') { st.ShiftNext(); if (st.Current == '=') { ret = OperatorCode.LeftShift; break; } throw new CodeEE("'<'は代入演算子として認識できません"); } break; case '>': if (next == '>') { st.ShiftNext(); if (st.Current == '=') { ret = OperatorCode.RightShift; break; } throw new CodeEE("'>'は代入演算子として認識できません"); } break; case '|': if (next == '=') { ret = OperatorCode.BitOr; } break; case '&': if (next == '=') { ret = OperatorCode.BitAnd; } break; case '^': if (next == '=') { ret = OperatorCode.BitXor; } break; } if (ret == OperatorCode.NULL) { throw new CodeEE("'" + cur + "'は代入演算子として認識できません"); } st.ShiftNext(); return(ret); }
public static Int64 ReadInt64(StringStream st, bool retZero) { Int64 significand = 0; int expBase = 0; int exponent = 0; int stStartPos = st.CurrentPosition; int stEndPos = st.CurrentPosition; int fromBase = 10; if (st.Current == '0') { char c = st.Next; if ((c == 'x') || (c == 'X')) { fromBase = 16; st.ShiftNext(); st.ShiftNext(); } else if ((c == 'b') || (c == 'B')) { fromBase = 2; st.ShiftNext(); st.ShiftNext(); } //8進法は互換性の問題から採用しない。 //else if (dchar.IsDigit(c)) //{ // fromBase = 8; // st.ShiftNext(); //} } if (retZero && st.Current != '+' && st.Current != '-' && !char.IsDigit(st.Current)) { if (fromBase != 16) { return(0); } else if (!hexadecimalDigits.Contains(st.Current)) { return(0); } } significand = readDigits(st, fromBase); if ((st.Current == 'p') || (st.Current == 'P')) { expBase = 2; } else if ((st.Current == 'e') || (st.Current == 'E')) { expBase = 10; } if (expBase != 0) { st.ShiftNext(); unchecked { exponent = (int)readDigits(st, fromBase); } } stEndPos = st.CurrentPosition; if ((expBase != 0) && (exponent != 0)) { double d = significand * Math.Pow(expBase, exponent); if ((double.IsNaN(d)) || (double.IsInfinity(d)) || (d > Int64.MaxValue) || (d < Int64.MinValue)) { throw new CodeEE("\"" + st.Substring(stStartPos, stEndPos) + "\"は64ビット符号付整数の範囲を超えています"); } significand = (Int64)d; } return(significand); }
/// <summary> /// endWithが見つかるまで読み込む。始点と終端のチェックは呼び出し側で行うこと。 /// エスケープあり。 /// </summary> /// <param name="st"></param> /// <returns></returns> public static string ReadString(StringStream st, StrEndWith endWith) { StringBuilder buffer = new StringBuilder(100); while (true) { switch (st.Current) { case '\0': goto end; case '\"': if (endWith == StrEndWith.DoubleQuotation) { goto end; } break; case '\'': if (endWith == StrEndWith.SingleQuotation) { goto end; } break; case ',': if ((endWith == StrEndWith.Comma) || (endWith == StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon)) { goto end; } break; case '(': case '[': case ';': if (endWith == StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon) { goto end; } break; case '\\': //エスケープ処理 st.ShiftNext(); //\を読み飛ばす switch (st.Current) { case StringStream.EndOfString: throw new CodeEE("エスケープ文字\\の後に文字がありません"); case '\n': break; case 's': buffer.Append(' '); break; case 'S': buffer.Append(' '); break; case 't': buffer.Append('\t'); break; case 'n': buffer.Append('\n'); break; default: buffer.Append(st.Current); break; } st.ShiftNext(); //\の次の文字を読み飛ばす continue; } buffer.Append(st.Current); st.ShiftNext(); } end: return(buffer.ToString()); }
/// <summary> /// 単語を文字列で取得。マクロ適用なし /// </summary> /// <param name="st"></param> /// <returns></returns> public static string ReadSingleIdentifier(StringStream st) { //1819 やや遅い。でもいずれやりたい //Match m = idReg.Match(st.RowString, st.CurrentPosition); //st.Jump(m.Length); //return m.Value; int start = st.CurrentPosition; char c; while (!st.EOS) { //switch (st.Current) //{ // case ' ': // case '\t': // case '+': // case '-': // case '*': // case '/': // case '%': // case '=': // case '!': // case '<': // case '>': // case '|': // case '&': // case '^': // case '~': // case '?': // case '#': // case ')': // case '}': // case ']': // case ',': // case ':': // case '(': // case '{': // case '[': // case '$': // case '\\': // case '\'': // case '\"': // case '@': // case '.': // case ';'://コメントに関しては直後に行われるであろうSkipWhiteSpaceなどが対応する。 // goto end; // case ' ': // if (!Config.SystemAllowFullSpace) // throw new CodeEE("予期しない全角スペースを発見しました(この警告はシステムオプション「" + Config.GetConfigName(ConfigCode.SystemAllowFullSpace) + "」により無視できます)"); // goto end; //} c = st.Current; if (kHashSet_ReadSingleIdentifier.Contains(c)) { goto end; } else if (c == ' ') { if (!Config.SystemAllowFullSpace) { throw new CodeEE("予期しない全角スペースを発見しました(この警告はシステムオプション「" + Config.GetConfigName(ConfigCode.SystemAllowFullSpace) + "」により無視できます)"); } goto end; } st.ShiftNext(); } end: return(st.Substring(start, st.CurrentPosition - start)); }
/// <summary> /// 次の有効な行を読む。LexicalAnalyzer経由でConfigを参照するのでConfig完成までつかわないこと。 /// </summary> public StringStream ReadEnabledLine() { string line = null; StringStream st = null; LineNo = nextNo; while (true) { line = reader.ReadLine(); LineNo++; nextNo++; if (line == null) { return(null); } if (line.Length == 0) { continue; } if (useRename && line.IndexOf("[[") >= 0 && line.IndexOf("]]") >= 0) { foreach (var pair in ParserMediator.RenameDic) { line = line.Replace(pair.Key, pair.Value); } } st = new StringStream(line); LexicalAnalyzer.SkipWhiteSpace(st); if (st.EOS) { continue; } if (st.Current == '}') { throw new CodeEE("予期しない行連結終端記号'}'が見つかりました"); } if (st.Current == '{') { if (line.Trim() != "{") { throw new CodeEE("行連結始端記号'{'の行に'{'以外の文字を含めることはできません"); } break; } return(st); } //curNoはこの後加算しない(始端記号の行を行番号とする) var b = new StringBuilder(); while (true) { line = reader.ReadLine(); nextNo++; if (line == null) { throw new CodeEE("行連結始端記号'{'が使われましたが終端記号'}'が見つかりません"); } if (useRename && line.IndexOf("[[") >= 0 && line.IndexOf("]]") >= 0) { foreach (var pair in ParserMediator.RenameDic) { line = line.Replace(pair.Key, pair.Value); } } var test = line.TrimStart(); if (test.Length > 0) { if (test[0] == '}') { if (test.Trim() != "}") { throw new CodeEE("行連結終端記号'}'の行に'}'以外の文字を含めることはできません"); } break; } if (test[0] == '{') { throw new CodeEE("予期しない行連結始端記号'{'が見つかりました"); } } b.Append(line); b.Append(" "); } st = new StringStream(b.ToString()); LexicalAnalyzer.SkipWhiteSpace(st); return(st); }
/// <summary> /// ファイル一つを読む /// </summary> /// <param name="filepath"></param> private void loadErb(string filepath, string filename, List<string> isOnlyEvent) { //読み込んだファイルのパスを記録 //一部ファイルの再読み込み時の処理用 labelDic.AddFilename(filename); EraStreamReader eReader = new EraStreamReader(); if (!eReader.Open(filepath, filename)) { output.PrintError(eReader.Filename + "のオープンに失敗しました"); return; } try { PPState ppstate = new PPState(); LogicalLine nextLine = new NullLine(); LogicalLine lastLine = new NullLine(); FunctionLabelLine lastLabelLine = null; StringStream st = null; string rowLine = null; ScriptPosition position = null; int funcCount = 0; if (Program.AnalysisMode) output.Print(" "); while ((st = eReader.ReadEnabledLine()) != null) { rowLine = st.RowString; position = new ScriptPosition(eReader.Filename, eReader.LineNo, rowLine); //1808alpha006 eramakerExの仕様通りにrenameを無制限に適用する if (Config.UseRenameFile && ParserMediator.RenameDic != null &&(rowLine.IndexOf("[[") >= 0) && (rowLine.IndexOf("]]") >= 0)) { foreach (KeyValuePair<string, string> pair in ParserMediator.RenameDic) rowLine = rowLine.Replace(pair.Key, pair.Value); st = new StringStream(rowLine); } //命令文の一部を[[]]置換できるのはよろしくないので、処理位置変更に対応 //全置換は弾く if (st.Current == '[' && st.Next != '[') { st.ShiftNext(); string token = LexicalAnalyzer.ReadSingleIdentifier(st); LexicalAnalyzer.SkipWhiteSpace(st); string token2 = LexicalAnalyzer.ReadSingleIdentifier(st); if ((string.IsNullOrEmpty(token)) || (st.Current != ']')) ParserMediator.Warn("[]の使い方が不正です", position, 1); ppstate.AddKeyWord(token, token2, position); st.ShiftNext(); if (!st.EOS) ParserMediator.Warn("[" + token + "]の後ろは無視されます。", position, 1); continue; } //if ((skip) || (Program.DebugMode && ifndebug) || (!Program.DebugMode && ifdebug)) // continue; if (ppstate.Disabled) continue; //ここまでプリプロセッサ if (st.Current == '#') { if ((lastLine == null) || !(lastLine is FunctionLabelLine)) { ParserMediator.Warn("関数宣言の直後以外で#行が使われています", position, 1); continue; } if (!LogicalLineParser.ParseSharpLine((FunctionLabelLine)lastLine, st, position, isOnlyEvent)) noError = false; continue; } if ((st.Current == '$') || (st.Current == '@')) { bool isFunction = (st.Current == '@'); nextLine = LogicalLineParser.ParseLabelLine(st, position, output); if (isFunction) { FunctionLabelLine label = (FunctionLabelLine)nextLine; lastLabelLine = label; if (label is InvalidLabelLine) { noError = false; ParserMediator.Warn(nextLine.ErrMes, position, 2); labelDic.AddInvalidLabel(label); } else// if (label is FunctionLabelLine) { labelDic.AddLabel(label); if (!label.IsEvent && (Config.WarnNormalFunctionOverloading || Program.AnalysisMode)) { FunctionLabelLine seniorLabel = labelDic.GetSameNameLabel(label); if (seniorLabel != null) { //output.NewLine(); ParserMediator.Warn("関数@" + label.LabelName + "は既に定義(" + seniorLabel.Position.Filename + "の" + seniorLabel.Position.LineNo.ToString() + "行目)されています", position, 1); funcCount = -1; } } funcCount++; if (Program.AnalysisMode && (Config.PrintCPerLine > 0 && (funcCount % Config.PrintCPerLine) == 0)) { output.NewLine(); output.Print(" "); } } } else { if (nextLine is GotoLabelLine) { GotoLabelLine gotoLabel = (GotoLabelLine)nextLine; gotoLabel.ParentLabelLine = lastLabelLine; if (lastLabelLine != null && !labelDic.AddLabelDollar(gotoLabel)) { ScriptPosition pos = labelDic.GetLabelDollar(gotoLabel.LabelName, lastLabelLine).Position; ParserMediator.Warn("ラベル名$" + gotoLabel.LabelName + "は既に同じ関数内(" + pos.Filename + "の" + pos.LineNo.ToString() + "行目)で使用されています", position, 2); } } } if (nextLine is InvalidLine) { noError = false; ParserMediator.Warn(nextLine.ErrMes, position, 2); } } else { //1808alpha006 処理位置変更 ////全置換はここで対応 ////1756beta1+++ 最初に全置換してしまうと関数定義を_Renameでとか論外なことができてしまうので永久封印した //if (ParserMediator.RenameDic != null && st.CurrentEqualTo("[[") && (rowLine.TrimEnd().IndexOf("]]") == rowLine.TrimEnd().Length - 2)) //{ // string replacedLine = st.Substring(); // foreach (KeyValuePair<string, string> pair in ParserMediator.RenameDic) // replacedLine = replacedLine.Replace(pair.Key, pair.Value); // st = new StringStream(replacedLine); //} nextLine = LogicalLineParser.ParseLine(st, position, output); if (nextLine == null) continue; if (nextLine is InvalidLine) { noError = false; ParserMediator.Warn(nextLine.ErrMes, position, 2); } } if (lastLabelLine == null) ParserMediator.Warn("関数が定義されるより前に行があります", position, 1); nextLine.ParentLabelLine = lastLabelLine; lastLine = addLine(nextLine, lastLine); } addLine(new NullLine(), lastLine); position = new ScriptPosition(eReader.Filename, -1, null); ppstate.FileEnd(position); } finally { eReader.Close(); } return; }
//#define FOO (~~) id to wc //#define BAR($1) (~~) idwithargs to wc(replaced) //#diseble FOOBAR //#dim piyo, i //#sdim puyo, j //static List<string> keywordsList = new List<string>(); private void analyzeSharpDefine(StringStream st, ScriptPosition position) { //LexicalAnalyzer.SkipWhiteSpace(st);呼び出し前に行う。 string srcID = LexicalAnalyzer.ReadSingleIdentifier(st); if (srcID == null) throw new CodeEE("置換元の識別子がありません", position); if (Config.ICVariable) srcID = srcID.ToUpper(); bool hasArg = st.Current == '(';//引数を指定する場合には直後に(が続いていなければならない。ホワイトスペースも禁止。 //1808a3 代入演算子許可(関数宣言用) WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, false, true); if (wc.EOL) { //throw new CodeEE("置換先の式がありません", position); //1808a3 空マクロの許可 DefineMacro nullmac = new DefineMacro(srcID, new WordCollection(), 0); idDic.AddMacro(nullmac); return; } List<string> argID = new List<string>(); string errMes = ""; int errLevel = -1; idDic.CheckUserMacroName(ref errMes, ref errLevel, srcID); if (errLevel >= 0) { ParserMediator.Warn(errMes, position, errLevel); if (errLevel >= 2) { noError = false; return; } } if (hasArg)//関数型マクロの引数解析 { wc.ShiftNext();//'('を読み飛ばす if (wc.Current.Type == ')') throw new CodeEE("関数型マクロの引数を0個にすることはできません", position); while (!wc.EOL) { IdentifierWord word = wc.Current as IdentifierWord; if (word == null) throw new CodeEE("置換元の引数指定の書式が間違っています", position); word.SetIsMacro(); string id = word.Code; if (argID.Contains(id)) throw new CodeEE("置換元の引数に同じ文字が2回以上使われています", position); argID.Add(id); wc.ShiftNext(); if (wc.Current.Type == ',') { wc.ShiftNext(); continue; } if (wc.Current.Type == ')') break; throw new CodeEE("置換元の引数指定の書式が間違っています", position); } if (wc.EOL) throw new CodeEE("')'が閉じられていません", position); wc.ShiftNext(); } if (wc.EOL) throw new CodeEE("置換先の式がありません", position); WordCollection destWc = new WordCollection(); while (!wc.EOL) { destWc.Add(wc.Current); wc.ShiftNext(); } if (hasArg)//関数型マクロの引数セット { while (!destWc.EOL) { IdentifierWord word = destWc.Current as IdentifierWord; if (word == null) { destWc.ShiftNext(); continue; } for (int i = 0; i < argID.Count; i++) { if (string.Equals(word.Code, argID[i], Config.SCVariable)) { destWc.Remove(); destWc.Insert(new MacroWord(i)); break; } } destWc.ShiftNext(); } destWc.Pointer = 0; } if (hasArg)//1808a3 関数型マクロの封印 throw new CodeEE("関数型マクロは宣言できません", position); DefineMacro mac = new DefineMacro(srcID, destWc, argID.Count); idDic.AddMacro(mac); }
/// <summary> /// 行頭の単語の取得。マクロ展開あり。ただし単語でないマクロ展開はしない。 /// </summary> /// <param name="st"></param> /// <returns></returns> public static IdentifierWord ReadFirstIdentifierWord(StringStream st) { int startpos = st.CurrentPosition; string str = ReadSingleIdentifier(st); if (string.IsNullOrEmpty(str)) throw new CodeEE("不正な文字で行が始まっています"); //1808a3 先頭1単語の展開をやめる。-命令の置換を禁止。 //if (UseMacro) //{ // int i = 0; // while (true) // { // DefineMacro macro = GlobalStatic.IdentifierDictionary.GetMacro(str); // i++; // if (i > MAX_EXPAND_MACRO) // throw new CodeEE("マクロの展開数が1文あたりの上限を超えました(自己参照・循環参照のおそれ)"); // if (macro == null) // break; // //単語(識別子一個)でないマクロが出現したらここでは処理しない // if (macro.IDWord == null) // { // st.CurrentPosition = startpos; // return null;//変数処理に任せる。 // } // str = macro.IDWord.Code; // } //} return new IdentifierWord(str); }
public static Int64 ReadInt64(StringStream st, bool retZero) { Int64 significand = 0; int expBase = 0; int exponent = 0; int stStartPos = st.CurrentPosition; int stEndPos = st.CurrentPosition; int fromBase = 10; if (st.Current == '0') { char c = st.Next; if ((c == 'x') || (c == 'X')) { fromBase = 16; st.ShiftNext(); st.ShiftNext(); } else if ((c == 'b') || (c == 'B')) { fromBase = 2; st.ShiftNext(); st.ShiftNext(); } //8進法は互換性の問題から採用しない。 //else if (dchar.IsDigit(c)) //{ // fromBase = 8; // st.ShiftNext(); //} } if (retZero && st.Current != '+' && st.Current != '-' && !char.IsDigit(st.Current)) { if (fromBase != 16) return 0; else if (!hexadecimalDigits.Contains(st.Current)) return 0; } significand = readDigits(st, fromBase); if ((st.Current == 'p') || (st.Current == 'P')) expBase = 2; else if ((st.Current == 'e') || (st.Current == 'E')) expBase = 10; if (expBase != 0) { st.ShiftNext(); unchecked { exponent = (int)readDigits(st, fromBase); } } stEndPos = st.CurrentPosition; if ((expBase != 0) && (exponent != 0)) { double d = significand * Math.Pow(expBase, exponent); if ((double.IsNaN(d)) || (double.IsInfinity(d)) || (d > Int64.MaxValue) || (d < Int64.MinValue)) throw new CodeEE("\"" + st.Substring(stStartPos, stEndPos) + "\"は64ビット符号付整数の範囲を超えています"); significand = (Int64)d; } return significand; }
/// <summary> /// 失敗したらCodeEE。OperatorManagerには頼らない /// "="の時、OperatorCode.Assignmentを返す。"=="の時はEqual /// </summary> /// <param name="st"></param> /// <returns></returns> public static OperatorCode ReadAssignmentOperator(StringStream st) { OperatorCode ret = OperatorCode.NULL; char cur = st.Current; st.ShiftNext(); char next = st.Current; switch (cur) { case '+': if (next == '+') ret = OperatorCode.Increment; else if (next == '=') ret = OperatorCode.Plus; break; case '-': if (next == '-') ret = OperatorCode.Decrement; else if (next == '=') ret = OperatorCode.Minus; break; case '*': if (next == '=') ret = OperatorCode.Mult; break; case '/': if (next == '=') ret = OperatorCode.Div; break; case '%': if (next == '=') ret = OperatorCode.Mod; break; case '=': if (next == '=') { ret = OperatorCode.Equal; break; } return OperatorCode.Assignment; case '<': if (next == '<') { st.ShiftNext(); if (st.Current == '=') { ret = OperatorCode.LeftShift; break; } throw new CodeEE("'<'は代入演算子として認識できません"); } break; case '>': if (next == '>') { st.ShiftNext(); if (st.Current == '=') { ret = OperatorCode.RightShift; break; } throw new CodeEE("'>'は代入演算子として認識できません"); } break; case '|': if (next == '=') ret = OperatorCode.BitOr; break; case '&': if (next == '=') ret = OperatorCode.BitAnd; break; case '^': if (next == '=') ret = OperatorCode.BitXor; break; } if (ret == OperatorCode.NULL) throw new CodeEE("'" + cur + "'は代入演算子として認識できません"); st.ShiftNext(); return ret; }
/// <summary> /// TIMES第二引数のみが使用する。 /// Convertクラスが発行する例外をそのまま投げるので適切に処理すること。 /// </summary> /// <param name="st"></param> /// <returns></returns> public static double ReadDouble(StringStream st) { int start = st.CurrentPosition; //大雑把に読み込んでエラー処理はConvertクラスに任せる。 //仮数小数部 if ((st.Current == '-')||(st.Current == '+')) { st.ShiftNext(); } while (!st.EOS) {//仮数部 char c = st.Current; if (char.IsDigit(c) || (c == '.')) { st.ShiftNext(); continue; } break; } if ((st.Current == 'e') || (st.Current == 'E')) { st.ShiftNext(); if (st.Current == '-') { st.ShiftNext(); } while (!st.EOS) {//指数部 char c = st.Current; if (char.IsDigit(c) || (c == '.')) { st.ShiftNext(); continue; } break; } } return Convert.ToDouble(st.Substring(start, st.CurrentPosition - start)); }
/// <summary> /// \@直後からの開始、\@の直後がCurrentになる /// </summary> /// <param name="st"></param> /// <returns></returns> public static YenAtSubWord AnalyseYenAt(StringStream st) { WordCollection w = Analyse(st, LexEndWith.Question, false, false); if (st.Current != '?') throw new CodeEE("\'\\@\'が使われましたが対応する\'?\'が見つかりません"); st.ShiftNext(); StrFormWord left = AnalyseFormattedString(st, FormStrEndWith.Sharp, true); if (st.Current != '#') { if (st.Current != '@') throw new CodeEE("\'\\@\',\'?\'が使われましたが対応する\'#\'が見つかりません"); st.ShiftNext(); ParserMediator.Warn("\'\\@\',\'?\'が使われましたが対応する\'#\'が見つかりません", GlobalStatic.Process.GetScaningLine(), 1, false, false); return new YenAtSubWord(w, left, null); } st.ShiftNext(); StrFormWord right = AnalyseFormattedString(st, FormStrEndWith.YenAt, true); if (st.Current != '@') throw new CodeEE("\'\\@\',\'?\',\'#\'が使われましたが対応する\'\\@\'が見つかりません"); st.ShiftNext(); return new YenAtSubWord(w, left, right); }
/// <summary> /// @"などの直後からの開始 /// return時にはendWithの文字がCurrentになっているはず。終端の適切さの検証は呼び出し元が行う。 /// </summary> /// <returns></returns> public static StrFormWord AnalyseFormattedString(StringStream st, FormStrEndWith endWith, bool trim) { List<string> strs = new List<string>(); List<SubWord> SWTs = new List<SubWord>(); StringBuilder buffer = new StringBuilder(100); while (true) { char cur = st.Current; switch (cur) { case '\n': case '\0': goto end; case '\"': if (endWith == FormStrEndWith.DoubleQuotation) goto end; buffer.Append(cur); break; case '#': if (endWith == FormStrEndWith.Sharp) goto end; buffer.Append(cur); break; case ',': if ((endWith == FormStrEndWith.Comma) || (endWith == FormStrEndWith.LeftParenthesis_Bracket_Comma_Semicolon)) goto end; buffer.Append(cur); break; case '(': case '[': case ';': if (endWith == FormStrEndWith.LeftParenthesis_Bracket_Comma_Semicolon) goto end; buffer.Append(cur); break; case '%': strs.Add(buffer.ToString()); buffer.Remove(0, buffer.Length); st.ShiftNext(); SWTs.Add(new PercentSubWord(Analyse(st, LexEndWith.Percent, false, false))); if (st.Current != '%') throw new CodeEE("\'%\'が使われましたが対応する\'%\'が見つかりません"); break; case '{': strs.Add(buffer.ToString()); buffer.Remove(0, buffer.Length); st.ShiftNext(); SWTs.Add(new CurlyBraceSubWord(Analyse(st, LexEndWith.RightCurlyBrace, false, false))); if (st.Current != '}') throw new CodeEE("\'{\'が使われましたが対応する\'}\'が見つかりません"); break; case '*': case '+': case '=': case '/': case '$': if (st.TripleSymbol()) { strs.Add(buffer.ToString()); buffer.Remove(0, buffer.Length); st.Jump(3); SWTs.Add(new TripleSymbolSubWord(cur)); continue; } else buffer.Append(cur); break; case '\\'://エスケープ文字の使用 st.ShiftNext(); cur = st.Current; switch (cur) { case '\0': throw new CodeEE("エスケープ文字\\の後に文字がありません"); case '\n': break; case 's': buffer.Append(' '); break; case 'S': buffer.Append(' '); break; case 't': buffer.Append('\t'); break; case 'n': buffer.Append('\n'); break; case '@'://\@~~?~~#~~\@ { if ((endWith == FormStrEndWith.YenAt) || (endWith == FormStrEndWith.Sharp)) goto end; strs.Add(buffer.ToString()); buffer.Remove(0, buffer.Length); st.ShiftNext(); SWTs.Add(AnalyseYenAt(st)); continue; } default: buffer.Append(cur); st.ShiftNext(); continue; } break; default: buffer.Append(cur); break; } st.ShiftNext(); } end: strs.Add(buffer.ToString()); string[] retStr = new string[strs.Count]; SubWord[] retSWTs = new SubWord[SWTs.Count]; strs.CopyTo(retStr); SWTs.CopyTo(retSWTs); if (trim && retStr.Length > 0) { retStr[0] = retStr[0].TrimStart(new char[] { ' ', '\t' }); retStr[retStr.Length - 1] = retStr[retStr.Length - 1].TrimEnd(new char[] { ' ', '\t' }); } return new StrFormWord(retStr, retSWTs); }
//static Regex reg = new Regex(@"[0-9A-Fa-f]+", RegexOptions.Compiled); private static Int64 readDigits(StringStream st, int fromBase) { int start = st.CurrentPosition; //1756 正規表現を使ってみたがほぼ変わらなかったので没 //Match m = reg.Match(st.RowString, st.CurrentPosition); //st.Jump(m.Length); char c = st.Current; if ((c == '-') || (c == '+')) { st.ShiftNext(); } if (fromBase == 10) { while (!st.EOS) { c = st.Current; if (char.IsDigit(c)) { st.ShiftNext(); continue; } break; } } else if (fromBase == 16) { while (!st.EOS) { c = st.Current; if (char.IsDigit(c) || hexadecimalDigits.Contains(c)) { st.ShiftNext(); continue; } break; } } else if (fromBase == 2) { while (!st.EOS) { c = st.Current; if (char.IsDigit(c)) { if ((c != '0') && (c != '1')) throw new CodeEE("二進法表記の中で使用できない文字が使われています"); st.ShiftNext(); continue; } break; } } string strInt = st.Substring(start, st.CurrentPosition - start); try { return Convert.ToInt64(strInt, fromBase); } catch (FormatException) { throw new CodeEE("\"" + strInt + "\"は整数値に変換できません"); } catch (OverflowException) { throw new CodeEE("\"" + strInt + "\"は64ビット符号付き整数の範囲を超えています"); } catch (ArgumentOutOfRangeException) { if (string.IsNullOrEmpty(strInt)) throw new CodeEE("数値として認識できる文字が必要です"); throw new CodeEE("文字列\"" + strInt + "\"は数値として認識できません"); } }
public static bool ParseSharpLine(FunctionLabelLine label, StringStream st, ScriptPosition position, List<string> OnlyLabel) { st.ShiftNext();//'#'を飛ばす string token = LexicalAnalyzer.ReadSingleIdentifier(st);//#~自体にはマクロ非適用 if (Config.ICFunction) token = token.ToUpper(); //#行として不正な行でもAnalyzeに行って引っかかることがあるので、先に存在しない#~は弾いてしまう if (token == null || (token != "SINGLE" && token != "LATER" && token != "PRI" && token != "ONLY" && token != "FUNCTION" && token != "FUNCTIONS" && token != "LOCALSIZE" && token != "LOCALSSIZE" && token != "DIM" && token != "DIMS")) { ParserMediator.Warn("解釈できない#行です", position, 1); return false; } try { WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, false, false); switch (token) { case "SINGLE": if (label.IsMethod) { ParserMediator.Warn("式中関数では#SINGLEは機能しません", position, 1); break; } else if (!label.IsEvent) { ParserMediator.Warn("イベント関数以外では#SINGLEは機能しません", position, 1); break; } else if (label.IsSingle) { ParserMediator.Warn("#SINGLEが重複して使われています", position, 1); break; } else if (label.IsOnly) { ParserMediator.Warn("#ONLYが指定されたイベント関数では#SINGLEは機能しません", position, 1); break; } label.IsSingle = true; break; case "LATER": if (label.IsMethod) { ParserMediator.Warn("式中関数では#LATERは機能しません", position, 1); break; } else if (!label.IsEvent) { ParserMediator.Warn("イベント関数以外では#LATERは機能しません", position, 1); break; } else if (label.IsLater) { ParserMediator.Warn("#LATERが重複して使われています", position, 1); break; } else if (label.IsOnly) { ParserMediator.Warn("#ONLYが指定されたイベント関数では#LATERは機能しません", position, 1); break; } else if (label.IsPri) ParserMediator.Warn("#PRIと#LATERが重複して使われています(この関数は2度呼ばれます)", position, 1); label.IsLater = true; break; case "PRI": if (label.IsMethod) { ParserMediator.Warn("式中関数では#PRIは機能しません", position, 1); break; } else if (!label.IsEvent) { ParserMediator.Warn("イベント関数以外では#PRIは機能しません", position, 1); break; } else if (label.IsPri) { ParserMediator.Warn("#PRIが重複して使われています", position, 1); break; } else if (label.IsOnly) { ParserMediator.Warn("#ONLYが指定されたイベント関数では#PRIは機能しません", position, 1); break; } else if (label.IsLater) ParserMediator.Warn("#PRIと#LATERが重複して使われています(この関数は2度呼ばれます)", position, 1); label.IsPri = true; break; case "ONLY": if (label.IsMethod) { ParserMediator.Warn("式中関数では#ONLYは機能しません", position, 1); break; } else if (!label.IsEvent) { ParserMediator.Warn("イベント関数以外では#ONLYは機能しません", position, 1); break; } else if (label.IsOnly) { ParserMediator.Warn("#ONLYが重複して使われています", position, 1); break; } else if (OnlyLabel.Contains(label.LabelName)) ParserMediator.Warn("このイベント関数\"@" + label.LabelName + "\"にはすでに#ONLYが宣言されています(この関数は実行されません)", position, 1); OnlyLabel.Add(label.LabelName); label.IsOnly = true; if (label.IsPri) { ParserMediator.Warn("このイベント関数には#PRIが宣言されていますが無視されます", position, 1); label.IsPri = false; } if (label.IsLater) { ParserMediator.Warn("このイベント関数には#LATERが宣言されていますが無視されます", position, 1); label.IsLater = false; } if (label.IsSingle) { ParserMediator.Warn("このイベント関数には#SINGLEが宣言されていますが無視されます", position, 1); label.IsSingle = false; } break; case "FUNCTION": case "FUNCTIONS": if (!string.IsNullOrEmpty(label.LabelName) && char.IsDigit(label.LabelName[0])) { ParserMediator.Warn("#" + token + "属性は関数名が数字で始まる関数には指定できません", position, 1); label.IsError = true; label.ErrMes = "関数名が数字で始まっています"; break; } if (label.IsMethod) { if ((label.MethodType == typeof(Int64) && token == "FUNCTION") || (label.MethodType == typeof(string) && token == "FUNCTIONS")) { ParserMediator.Warn("関数" + label.LabelName + "にはすでに#" + token + "が宣言されています(この行は無視されます)", position, 1); return false; } if (label.MethodType == typeof(Int64) && token == "FUNCTIONS") ParserMediator.Warn("関数" + label.LabelName + "にはすでに#FUNCTIONが宣言されています", position, 2); else if (label.MethodType == typeof(string) && token == "FUNCTION") ParserMediator.Warn("関数" + label.LabelName + "にはすでに#FUNCTIONSが宣言されています", position, 2); return false; } if (label.Depth == 0) { ParserMediator.Warn("システム関数に#" + token + "が指定されています", position, 2); return false; } label.IsMethod = true; label.Depth = 0; if (token == "FUNCTIONS") label.MethodType = typeof(string); else label.MethodType = typeof(Int64); if (label.IsPri) { ParserMediator.Warn("式中関数では#PRIは機能しません", position, 1); label.IsPri = false; } if (label.IsLater) { ParserMediator.Warn("式中関数では#LATERは機能しません", position, 1); label.IsLater = false; } if (label.IsSingle) { ParserMediator.Warn("式中関数では#SINGLEは機能しません", position, 1); label.IsSingle = false; } if (label.IsOnly) { ParserMediator.Warn("式中関数では#ONLYは機能しません", position, 1); label.IsOnly = false; } break; case "LOCALSIZE": case "LOCALSSIZE": { //イベント関数では指定しても無視される if (label.IsEvent) { ParserMediator.Warn("イベント関数では#" + token + "による" + token.Substring(0, token.Length - 4)+ "のサイズ指定は無視されます", position, 1); break; } if (wc.EOL) { ParserMediator.Warn("#" + token + "の後に有効な数値が指定されていません", position, 2); break; } IOperandTerm arg = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL); SingleTerm sizeTerm = arg.Restructure(null) as SingleTerm; if ((sizeTerm == null) || (sizeTerm.GetOperandType() != typeof(Int64))) { ParserMediator.Warn("#" + token + "の後に有効な定数式が指定されていません", position, 2); break; } if (sizeTerm.Int <= 0) { ParserMediator.Warn("#" + token + "に0以下の値(" + sizeTerm.Int.ToString() + ")が与えられました。設定は無視されます", position, 1); break; } if (sizeTerm.Int >= Int32.MaxValue) { ParserMediator.Warn("#" + token + "に大きすぎる値(" + sizeTerm.Int.ToString() + ")が与えられました。設定は無視されます", position, 1); break; } int size = (int)sizeTerm.Int; if (token == "LOCALSIZE") { if (label.LocalLength > 0) ParserMediator.Warn("この関数にはすでに#LOCALSIZEが定義されています。(以前の定義は無視されます)", position, 1); label.LocalLength = size; } else { if (label.LocalsLength > 0) ParserMediator.Warn("この関数にはすでに#LOCALSSIZEが定義されています。(以前の定義は無視されます)", position, 1); label.LocalsLength = size; } } break; case "DIM": case "DIMS": { UserDefinedVariableData data = UserDefinedVariableData.Create(wc, token == "DIMS", true, position); if (!label.AddPrivateVariable(data)) { ParserMediator.Warn("変数名" + data.Name + "は既に使用されています", position, 2); return false; } break; } default: ParserMediator.Warn("解釈できない#行です", position, 1); break; } if (!wc.EOL) ParserMediator.Warn("#の識別子の後に余分な文字があります", position, 1); } catch (Exception e) { ParserMediator.Warn(e.Message, position, 2); goto err; } return true; err: return false; }
/// <summary> /// 失敗したらCodeEE。OperatorManagerには頼らない /// OperatorCode.Assignmentを返すことがある。 /// </summary> /// <param name="st"></param> /// <returns></returns> public static OperatorCode ReadOperator(StringStream st, bool allowAssignment) { char cur = st.Current; st.ShiftNext(); char next = st.Current; switch (cur) { case '+': if (next == '+') { st.ShiftNext(); return OperatorCode.Increment; } return OperatorCode.Plus; case '-': if (next == '-') { st.ShiftNext(); return OperatorCode.Decrement; } return OperatorCode.Minus; case '*': return OperatorCode.Mult; case '/': return OperatorCode.Div; case '%': return OperatorCode.Mod; case '=': if (next == '=') { st.ShiftNext(); return OperatorCode.Equal; } if (allowAssignment) return OperatorCode.Assignment; throw new CodeEE("予期しない代入演算子'='を発見しました(等価比較には'=='を使用してください)"); case '!': if (next == '=') { st.ShiftNext(); return OperatorCode.NotEqual; } else if (next == '&') { st.ShiftNext(); return OperatorCode.Nand; } else if (next == '|') { st.ShiftNext(); return OperatorCode.Nor; } return OperatorCode.Not; case '<': if (next == '=') { st.ShiftNext(); return OperatorCode.LessEqual; } else if (next == '<') { st.ShiftNext(); return OperatorCode.LeftShift; } return OperatorCode.Less; case '>': if (next == '=') { st.ShiftNext(); return OperatorCode.GreaterEqual; } else if (next == '>') { st.ShiftNext(); return OperatorCode.RightShift; } return OperatorCode.Greater; case '|': if (next == '|') { st.ShiftNext(); return OperatorCode.Or; } return OperatorCode.BitOr; case '&': if (next == '&') { st.ShiftNext(); return OperatorCode.And; } return OperatorCode.BitAnd; case '^': if (next == '^') { st.ShiftNext(); return OperatorCode.Xor; } return OperatorCode.BitXor; case '~': return OperatorCode.BitNot; case '?': return OperatorCode.Ternary_a; case '#': return OperatorCode.Ternary_b; } throw new CodeEE("'" + cur + "'は演算子として認識できません"); }
public static LogicalLine ParseLine(StringStream stream, ScriptPosition position, EmueraConsole console) { int lineNo = position.LineNo; string errMes = ""; LexicalAnalyzer.SkipWhiteSpace(stream);//先頭のホワイトスペースを読み飛ばす if (stream.EOS) return null; //コメント行かどうかはここに来る前に判定しておく try { #region 前置インクリメント、デクリメント行 if (stream.Current == '+' || stream.Current == '-') { char op = stream.Current; WordCollection wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, false, false); OperatorWord opWT = wc.Current as OperatorWord; if ((opWT == null)|| ((opWT.Code != OperatorCode.Increment) &&(opWT.Code != OperatorCode.Decrement)) ) { if (op == '+') errMes = "行が\'+\'から始まっていますが、インクリメントではありません"; else errMes = "行が\'-\'から始まっていますが、デクリメントではありません"; goto err; } wc.ShiftNext(); //token = EpressionParser.単語一個分取得(wc) //token非変数 //token文字列形 //token変更不可能 //if (wc != EOS) // return new InstructionLine(position, FunctionIdentifier.SETFunction, opWT.Code, wc, null); } #endregion IdentifierWord idWT = LexicalAnalyzer.ReadFirstIdentifierWord(stream); if (idWT != null) { FunctionIdentifier func = GlobalStatic.IdentifierDictionary.GetFunctionIdentifier(idWT.Code); //命令文 if (func != null)//関数文 { if (stream.EOS) //引数の無い関数 return new InstructionLine(position, func, stream); if ((stream.Current != ' ') && (stream.Current != '\t') && (!Config.SystemAllowFullSpace || (stream.Current != ' '))) { errMes = "命令で行が始まっていますが、命令の直後に半角スペース・タブ以外の文字が来ています"; goto err; } stream.ShiftNext(); return new InstructionLine(position, func, stream); } } LexicalAnalyzer.SkipWhiteSpace(stream); if (stream.EOS) { errMes = "解釈できない行です"; goto err; } //命令行ではない→代入行のはず stream.Seek(0, System.IO.SeekOrigin.Begin); OperatorCode assignOP = OperatorCode.NULL; WordCollection wc1 = LexicalAnalyzer.Analyse(stream, LexEndWith.Operator, false, false); //if (idWT != null) // wc1.Collection.Insert(0, idWT); try { assignOP = LexicalAnalyzer.ReadAssignmentOperator(stream); } catch(CodeEE) { errMes = "解釈できない行です"; goto err; } //eramaker互換警告 //stream.Jump(-1); //if ((stream.Current != ' ') && (stream.Current != '\t')) //{ // errMes = "変数で行が始まっていますが、演算子の直前に半角スペースまたはタブがありません"; // goto err; //} //stream.ShiftNext(); if (assignOP == OperatorCode.Equal) { if (console != null) ParserMediator.Warn("代入演算子に\"==\"が使われています", position, 0); //"=="を代入文に使うのは本当はおかしいが結構使われているので仕様にする assignOP = OperatorCode.Assignment; } return new InstructionLine(position, FunctionIdentifier.SETFunction, assignOP, wc1, stream); err: return new InvalidLine(position, errMes); } catch (CodeEE e) { System.Media.SystemSounds.Hand.Play(); return new InvalidLine(position, e.Message); } }
/// <summary> /// 単語を文字列で取得。マクロ適用なし /// </summary> /// <param name="st"></param> /// <returns></returns> public static string ReadSingleIdentifier(StringStream st) { int start = st.CurrentPosition; while (!st.EOS) { switch (st.Current) { case ' ': case '\t': case '+': case '-': case '*': case '/': case '%': case '=': case '!': case '<': case '>': case '|': case '&': case '^': case '~': case '?': case '#': case ')': case '}': case ']': case ',': case ':': case '(': case '{': case '[': case '$': case '\\': case '\'': case '\"': case '@': case '.': case ';'://コメントに関しては直後に行われるであろうSkipWhiteSpaceなどが対応する。 goto end; case ' ': if (!Config.SystemAllowFullSpace) throw new CodeEE("予期しない全角スペースを発見しました"); goto end; } st.ShiftNext(); } end: return st.Substring(start, st.CurrentPosition - start); }
private void analyzeSharpDim(StringStream st, ScriptPosition position, bool dims) { WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, false, false); UserDefinedVariableData data = UserDefinedVariableData.Create(wc, dims, false, position); VariableToken var = parentProcess.VEvaluator.VariableData.CreateUserDefVariable(data); idDic.AddUseDefinedVariable(var); }
/// <summary> /// 解析できるものは関数宣言や式のみ。FORM文字列や普通の文字列を送ってはいけない /// return時にはendWithの文字がCurrentになっているはず。終端の適切さの検証は呼び出し元が行う。 /// </summary> /// <returns></returns> public static WordCollection Analyse(StringStream st, LexEndWith endWith, bool isPrintV, bool allowAssignment) { WordCollection ret = new WordCollection(); int nestBracketS = 0; //int nestBracketM = 0; int nestBracketL = 0; while (true) { switch (st.Current) { case '\n': case '\0': goto end; case ' ': case '\t': st.ShiftNext(); continue; case ' ': if (!Config.SystemAllowFullSpace) throw new CodeEE("字句解析中に予期しない全角スペースを発見しました"); st.ShiftNext(); continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ret.Add(new LiteralIntegerWord(ReadInt64(st, false))); break; case '+': case '-': case '*': case '/': case '%': case '=': case '!': case '<': case '>': case '|': case '&': case '^': case '~': case '?': case '#': if ((nestBracketS == 0) && (nestBracketL == 0)) { if (endWith == LexEndWith.Operator) goto end;//代入演算子のはずである。呼び出し元がチェックするはず else if ((endWith == LexEndWith.Percent) && (st.Current == '%')) goto end; else if ((endWith == LexEndWith.Question) && (st.Current == '?')) goto end; } ret.Add(new OperatorWord(ReadOperator(st, allowAssignment))); break; case ')': ret.Add(new SymbolWord(')')); nestBracketS--; st.ShiftNext(); continue; case ']': ret.Add(new SymbolWord(']')); nestBracketL--; st.ShiftNext(); continue; case '(': ret.Add(new SymbolWord('(')); nestBracketS++; st.ShiftNext(); continue; case '[': if (st.Next == '[') { //throw new CodeEE("字句解析中に予期しない文字'[['を発見しました"); ////1808alpha006 rename処理変更 //1808beta009 ここだけ戻す //現在の処理だとここに来た時点でrename失敗確定だが警告内容を元に戻すため if (ParserMediator.RenameDic == null) throw new CodeEE("字句解析中に予期しない文字\"[[\"を発見しました"); int start = st.CurrentPosition; int find = st.Find("]]"); if (find <= 2) { if (find == 2) throw new CodeEE("空の[[]]です"); else throw new CodeEE("対応する\"]]\"のない\"[[\"です"); } string key = st.Substring(start, find + 2); string value = null; if (!ParserMediator.RenameDic.TryGetValue(key, out value)) throw new CodeEE("字句解析中に置換(rename)できない符号" + key + "を発見しました"); st.Replace(start, find + 2, value); continue;//その場から再度解析スタート } ret.Add(new SymbolWord('[')); nestBracketL++; st.ShiftNext(); continue; case ':': ret.Add(new SymbolWord(':')); st.ShiftNext(); continue; case ',': if ((endWith == LexEndWith.Comma) && (nestBracketS == 0))// && (nestBracketL == 0)) goto end; ret.Add(new SymbolWord(',')); st.ShiftNext(); continue; //case '}': ret.Add(new SymbolWT('}')); nestBracketM--; continue; //case '{': ret.Add(new SymbolWT('{')); nestBracketM++; continue; case '\'': if (!isPrintV) throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました"); st.ShiftNext(); ret.Add(new LiteralStringWord(ReadString(st, StrEndWith.Comma))); if (st.Current == ',') goto case ',';//続きがあるなら,の処理へ。それ以外は行終端のはず goto end; case '}': if (endWith == LexEndWith.RightCurlyBrace) goto end; throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました"); case '\"': st.ShiftNext(); ret.Add(new LiteralStringWord(ReadString(st, StrEndWith.DoubleQuotation))); if (st.Current != '\"') throw new CodeEE("\"が閉じられていません"); st.ShiftNext(); break; case '@': if (st.Next != '\"') { ret.Add(new SymbolWord('@')); st.ShiftNext(); continue; } st.ShiftNext(); st.ShiftNext(); ret.Add(AnalyseFormattedString(st, FormStrEndWith.DoubleQuotation, false)); if (st.Current != '\"') throw new CodeEE("\"が閉じられていません"); st.ShiftNext(); break; case '\\': if (st.Next != '@') throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました"); { st.Jump(2); ret.Add(new StrFormWord(new string[] { "", "" }, new SubWord[] { AnalyseYenAt(st) })); } break; case '{': case '$': case '.': throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました"); case ';'://1807 行中コメント if (st.CurrentEqualTo(";#;") && Program.DebugMode) { st.Jump(3); break; } else if (st.CurrentEqualTo(";!;")) { st.Jump(3); break; } st.Seek(0, System.IO.SeekOrigin.End); goto end; default: { ret.Add(new IdentifierWord(ReadSingleIdentifier(st))); break; } } } end: if ((nestBracketS != 0) || (nestBracketL != 0)) { if (nestBracketS < 0) throw new CodeEE("字句解析中に対応する'('のない')'を発見しました"); else if (nestBracketS > 0) throw new CodeEE("字句解析中に対応する')'のない'('を発見しました"); if (nestBracketL < 0) throw new CodeEE("字句解析中に対応する'['のない']'を発見しました"); else if (nestBracketL > 0) throw new CodeEE("字句解析中に対応する']'のない'['を発見しました"); } if (UseMacro) return expandMacro(ret); return ret; }
public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm) { WordCollection destWc = line.PopAssignmentDestStr(); IOperandTerm[] destTerms = ExpressionParser.ReduceArguments(destWc, ArgsEndWith.EoL, false); SpSetArgument ret = null; if ((destTerms.Length == 0) || (destTerms[0] == null)) {assignwarn("代入文の代入先変数の読み取りに失敗しました", line, 2, false); return null;} if (destTerms.Length != 1) {assignwarn("代入文の左辺に余分な','があります", line, 2, false); return null;} VariableTerm varTerm = destTerms[0] as VariableTerm; if (varTerm == null) {// assignwarn("代入文の左辺に変数以外を指定することはできません", line, 2, false); return null; } else if (varTerm.Identifier.Readonly) { assignwarn("代入文に変更できない変数を指定することはできません", line, 2, false); return null; } varTerm.Restructure(exm); StringStream st = line.PopArgumentPrimitive(); if (st == null) st = new StringStream(""); OperatorCode op = line.AssignOperator; IOperandTerm src = null; if(varTerm.IsInteger) { if((op == OperatorCode.Increment)||(op == OperatorCode.Decrement)) { LexicalAnalyzer.SkipWhiteSpace(st); if (!st.EOS) { if (op == OperatorCode.Increment) {assignwarn("インクリメント行でインクリメント以外の処理が定義されています", line, 2, false);return null;} else {assignwarn("デクリメント行でデクリメント以外の処理が定義されています", line, 2, false);return null;} } ret = new SpSetArgument(varTerm, null); ret.IsConst = true; if (op == OperatorCode.Increment) ret.ConstInt = 1; else ret.ConstInt = -1; ret.AddConst = true; return ret; } WordCollection srcWc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, false, false); IOperandTerm[] srcTerms = ExpressionParser.ReduceArguments(srcWc, ArgsEndWith.EoL, false); if ((srcTerms.Length == 0) || (srcTerms[0] == null)) {assignwarn("代入文の右辺の読み取りに失敗しました", line, 2, false); return null;} if (srcTerms.Length != 1) { if(op != OperatorCode.Assignment) {assignwarn("複合代入演算では右辺に複数の値を含めることはできません", line, 2, false); return null;} bool allConst = true; Int64[] constValues = new Int64[srcTerms.Length]; for (int i = 0; i < srcTerms.Length; i++) { if (srcTerms[i] == null) { assignwarn("代入式の右辺の値は省略できません", line, 2, false); return null; } if (!srcTerms[i].IsInteger) { assignwarn("数値型変数に文字列は代入できません", line, 2, false); return null; } srcTerms[i] = srcTerms[i].Restructure(exm); if (allConst && (srcTerms[i] is SingleTerm)) constValues[i] = srcTerms[i].GetIntValue(null); else allConst = false; } SpSetArrayArgument arrayarg = new SpSetArrayArgument(varTerm, srcTerms, constValues); arrayarg.IsConst = allConst; return arrayarg; } if(!srcTerms[0].IsInteger) {assignwarn("数値型変数に文字列は代入できません", line, 2, false); return null;} src = srcTerms[0].Restructure(exm); if(op == OperatorCode.Assignment) { ret = new SpSetArgument(varTerm, src); if(src is SingleTerm) { ret.IsConst = true; ret.AddConst = false; ret.ConstInt = src.GetIntValue(null); } return ret; } if((op == OperatorCode.Plus)||(op == OperatorCode.Minus)) { if(src is SingleTerm) { ret = new SpSetArgument(varTerm, null); ret.IsConst = true; ret.AddConst = true; if (op == OperatorCode.Plus) ret.ConstInt = src.GetIntValue(null); else ret.ConstInt = -src.GetIntValue(null); return ret; } } src = OperatorMethodManager.ReduceBinaryTerm(op,varTerm, src); return new SpSetArgument(varTerm, src); } else { if (op == OperatorCode.Assignment) { LexicalAnalyzer.SkipHalfSpace(st);//文字列の代入なら半角スペースだけを読み飛ばす //eramakerは代入文では妙なTrim()をする。半端にしか再現できないがとりあえずtrim = true StrFormWord sfwt = LexicalAnalyzer.AnalyseFormattedString(st, FormStrEndWith.EoL, true); IOperandTerm term = ExpressionParser.ToStrFormTerm(sfwt); src = term.Restructure(exm); ret = new SpSetArgument(varTerm, src); if (src is SingleTerm) { ret.IsConst = true; ret.AddConst = false; ret.ConstStr = src.GetStrValue(null); return ret; } return new SpSetArgument(varTerm, src); } else if ((op == OperatorCode.Mult)||(op == OperatorCode.Plus)) { WordCollection srcWc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, false, false); IOperandTerm[] srcTerms = ExpressionParser.ReduceArguments(srcWc, ArgsEndWith.EoL, false); if ((srcTerms.Length == 0) || (srcTerms[0] == null)) {assignwarn("代入文の右辺の読み取りに失敗しました", line, 2, false); return null;} if (srcTerms.Length != 1) {assignwarn("代入文の右辺に余分な','があります", line, 2, false); return null;} src = srcTerms[0].Restructure(exm); src = OperatorMethodManager.ReduceBinaryTerm(op, varTerm, src); return new SpSetArgument(varTerm, src); } assignwarn("代入式に使用できない演算子が使われました", line, 2, false); return null; } }
/// <summary> /// 単語の取得。マクロ展開あり。関数型マクロ展開なし /// </summary> /// <param name="st"></param> /// <returns></returns> public static IdentifierWord ReadSingleIdentifierWord(StringStream st) { string str = ReadSingleIdentifier(st); if (string.IsNullOrEmpty(str)) return null; if (UseMacro) { int i = 0; while (true) { DefineMacro macro = GlobalStatic.IdentifierDictionary.GetMacro(str); i++; if (i > MAX_EXPAND_MACRO) throw new CodeEE("マクロの展開数が1文あたりの上限値" + MAX_EXPAND_MACRO.ToString() + "を超えました(自己参照・循環参照のおそれ)"); if (macro == null) break; if (macro.IDWord != null) throw new CodeEE("マクロ" + macro.Keyword + "はこの文脈では使用できません(1単語に置き換えるマクロのみが使用できます)"); str = macro.IDWord.Code; } } return new IdentifierWord(str); }
public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments) { string str = arguments[0].GetStrValue(exm); if (str == null || str == "") return (0); //全角文字が入ってるなら無条件で0を返す if (str.Length < LangManager.GetStrlenLang(str)) return (0); StringStream st = new StringStream(str); if (!char.IsDigit(st.Current) && st.Current != '+' && st.Current != '-') return (0); else if ((st.Current == '+' || st.Current == '-') && !char.IsDigit(st.Next)) return (0); Int64 ret = LexicalAnalyzer.ReadInt64(st, true); if (!st.EOS) { if (st.Current == '.') { st.ShiftNext(); while (!st.EOS) { if (!char.IsDigit(st.Current)) return (0); st.ShiftNext(); } } else return (0); } return ret; }
public static LogicalLine ParseLabelLine(StringStream stream, ScriptPosition position, EmueraConsole console) { bool isFunction = (stream.Current == '@'); int lineNo = position.LineNo; string labelName = ""; string errMes = ""; try { int warnLevel = -1; stream.ShiftNext();//@か$を除去 WordCollection wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, false, true); if (wc.EOL || !(wc.Current is IdentifierWord)) { errMes = "関数名が不正であるか存在しません"; goto err; } labelName = ((IdentifierWord)wc.Current).Code; wc.ShiftNext(); if (Config.ICVariable) labelName = labelName.ToUpper(); GlobalStatic.IdentifierDictionary.CheckUserLabelName(ref errMes, ref warnLevel, isFunction, labelName); if (warnLevel >= 0) { if (warnLevel >= 2) goto err; ParserMediator.Warn(errMes, position, warnLevel); } if (!isFunction)//$ならこの時点で終了 { if (!wc.EOL) ParserMediator.Warn("$で始まるラベルに引数が設定されています", position, 1); return new GotoLabelLine(position, labelName); } //labelName = LexicalAnalyzer.ReadString(stream, StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon); //labelName = labelName.Trim(); //if (Config.ICVariable) // labelName = labelName.ToUpper(); //GlobalStatic.IdentifierDictionary.CheckUserLabelName(ref errMes, ref warnLevel, isFunction, labelName); //if(warnLevel >= 0) //{ // if (warnLevel >= 2) // goto err; // ParserMediator.Warn(errMes, position, warnLevel); //} //if (!isFunction)//$ならこの時点で終了 //{ // LexicalAnalyzer.SkipWhiteSpace(stream); // if (!stream.EOS) // ParserMediator.Warn("$で始まるラベルに引数が設定されています", position, 1); // return new GotoLabelLine(position, labelName); //} ////関数名部分に_renameを使えないように変更 //if (ParserMediator.RenameDic != null && ((stream.ToString().IndexOf("[[") >= 0) && (stream.ToString().IndexOf("]]") >= 0))) //{ // string line = stream.ToString(); // foreach (KeyValuePair<string, string> pair in ParserMediator.RenameDic) // line = line.Replace(pair.Key, pair.Value); // stream = new StringStream(line); //} //WordCollection wc = null; //wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, false, true); if (Program.AnalysisMode) console.PrintC("@" + labelName, false); FunctionLabelLine funclabelLine = new FunctionLabelLine(position, labelName, wc); if (IdentifierDictionary.IsEventLabelName(labelName)) { funclabelLine.IsEvent = true; funclabelLine.IsSystem = true; funclabelLine.Depth = 0; } else if (IdentifierDictionary.IsSystemLabelName(labelName)) { funclabelLine.IsSystem = true; funclabelLine.Depth = 0; } return funclabelLine; } catch (CodeEE e) { errMes = e.Message; } err: System.Media.SystemSounds.Hand.Play(); if (isFunction) { if(labelName.Length == 0) labelName = "<Error>"; return new InvalidLabelLine(position, labelName, errMes); } return new InvalidLine(position, errMes); }
/// <summary> /// @"などの直後からの開始 /// return時にはendWithの文字がCurrentになっているはず。終端の適切さの検証は呼び出し元が行う。 /// </summary> /// <returns></returns> public static StrFormWord AnalyseFormattedString(StringStream st, FormStrEndWith endWith, bool trim) { List <string> strs = new List <string>(); List <SubWord> SWTs = new List <SubWord>(); StringBuilder buffer = new StringBuilder(100); while (true) { char cur = st.Current; switch (cur) { case '\n': case '\0': goto end; case '\"': if (endWith == FormStrEndWith.DoubleQuotation) { goto end; } buffer.Append(cur); break; case '#': if (endWith == FormStrEndWith.Sharp) { goto end; } buffer.Append(cur); break; case ',': if ((endWith == FormStrEndWith.Comma) || (endWith == FormStrEndWith.LeftParenthesis_Bracket_Comma_Semicolon)) { goto end; } buffer.Append(cur); break; case '(': case '[': case ';': if (endWith == FormStrEndWith.LeftParenthesis_Bracket_Comma_Semicolon) { goto end; } buffer.Append(cur); break; case '%': strs.Add(buffer.ToString()); buffer.Remove(0, buffer.Length); st.ShiftNext(); SWTs.Add(new PercentSubWord(Analyse(st, LexEndWith.Percent, LexAnalyzeFlag.None))); if (st.Current != '%') { throw new CodeEE("\'%\'が使われましたが対応する\'%\'が見つかりません"); } break; case '{': strs.Add(buffer.ToString()); buffer.Remove(0, buffer.Length); st.ShiftNext(); SWTs.Add(new CurlyBraceSubWord(Analyse(st, LexEndWith.RightCurlyBrace, LexAnalyzeFlag.None))); if (st.Current != '}') { throw new CodeEE("\'{\'が使われましたが対応する\'}\'が見つかりません"); } break; case '*': case '+': case '=': case '/': case '$': if (!Config.SystemIgnoreTripleSymbol && st.TripleSymbol()) { strs.Add(buffer.ToString()); buffer.Remove(0, buffer.Length); st.Jump(3); SWTs.Add(new TripleSymbolSubWord(cur)); continue; } else { buffer.Append(cur); } break; case '\\': //エスケープ文字の使用 st.ShiftNext(); cur = st.Current; switch (cur) { case '\0': throw new CodeEE("エスケープ文字\\の後に文字がありません"); case '\n': break; case 's': buffer.Append(' '); break; case 'S': buffer.Append(' '); break; case 't': buffer.Append('\t'); break; case 'n': buffer.Append('\n'); break; case '@': //\@~~?~~#~~\@ { if ((endWith == FormStrEndWith.YenAt) || (endWith == FormStrEndWith.Sharp)) { goto end; } strs.Add(buffer.ToString()); buffer.Remove(0, buffer.Length); st.ShiftNext(); SWTs.Add(AnalyseYenAt(st)); continue; } default: buffer.Append(cur); st.ShiftNext(); continue; } break; default: buffer.Append(cur); break; } st.ShiftNext(); } end: strs.Add(buffer.ToString()); string[] retStr = new string[strs.Count]; SubWord[] retSWTs = new SubWord[SWTs.Count]; strs.CopyTo(retStr); SWTs.CopyTo(retSWTs); if (trim && retStr.Length > 0) { retStr[0] = retStr[0].TrimStart(new char[] { ' ', '\t' }); retStr[retStr.Length - 1] = retStr[retStr.Length - 1].TrimEnd(new char[] { ' ', '\t' }); } return(new StrFormWord(retStr, retSWTs)); }
public static LogicalLine ParseLine(string str, EmueraConsole console) { ScriptPosition position = new ScriptPosition(str); StringStream stream = new StringStream(str); return ParseLine(stream, position, console); }
//static Regex reg = new Regex(@"[0-9A-Fa-f]+", RegexOptions.Compiled); private static Int64 readDigits(StringStream st, int fromBase) { int start = st.CurrentPosition; //1756 正規表現を使ってみたがほぼ変わらなかったので没 //Match m = reg.Match(st.RowString, st.CurrentPosition); //st.Jump(m.Length); char c = st.Current; if ((c == '-') || (c == '+')) { st.ShiftNext(); } if (fromBase == 10) { while (!st.EOS) { c = st.Current; if (char.IsDigit(c)) { st.ShiftNext(); continue; } break; } } else if (fromBase == 16) { while (!st.EOS) { c = st.Current; if (char.IsDigit(c) || hexadecimalDigits.Contains(c)) { st.ShiftNext(); continue; } break; } } else if (fromBase == 2) { while (!st.EOS) { c = st.Current; if (char.IsDigit(c)) { if ((c != '0') && (c != '1')) { throw new CodeEE("二進法表記の中で使用できない文字が使われています"); } st.ShiftNext(); continue; } break; } } string strInt = st.Substring(start, st.CurrentPosition - start); try { return(Convert.ToInt64(strInt, fromBase)); } catch (FormatException) { throw new CodeEE("\"" + strInt + "\"は整数値に変換できません"); } catch (OverflowException) { throw new CodeEE("\"" + strInt + "\"は64ビット符号付き整数の範囲を超えています"); } catch (ArgumentOutOfRangeException) { if (string.IsNullOrEmpty(strInt)) { throw new CodeEE("数値として認識できる文字が必要です"); } throw new CodeEE("文字列\"" + strInt + "\"は数値として認識できません"); } }
/// <summary> /// 字句解析・構文解析用。文字列直前の半角スペースを飛ばす。性質上、半角スペースのみを見る。 /// </summary> public static int SkipHalfSpace(StringStream st) { int count = 0; while (st.Current == ' ') { count++; st.ShiftNext(); } return count; }
/// <summary> /// 失敗したらCodeEE。OperatorManagerには頼らない /// OperatorCode.Assignmentを返すことがある。 /// </summary> /// <param name="st"></param> /// <returns></returns> public static OperatorCode ReadOperator(StringStream st, bool allowAssignment) { char cur = st.Current; st.ShiftNext(); char next = st.Current; switch (cur) { case '+': if (next == '+') { st.ShiftNext(); return(OperatorCode.Increment); } return(OperatorCode.Plus); case '-': if (next == '-') { st.ShiftNext(); return(OperatorCode.Decrement); } return(OperatorCode.Minus); case '*': return(OperatorCode.Mult); case '/': return(OperatorCode.Div); case '%': return(OperatorCode.Mod); case '=': if (next == '=') { st.ShiftNext(); return(OperatorCode.Equal); } if (allowAssignment) { return(OperatorCode.Assignment); } throw new CodeEE("予期しない代入演算子'='を発見しました(等価比較には'=='を使用してください)"); case '!': if (next == '=') { st.ShiftNext(); return(OperatorCode.NotEqual); } else if (next == '&') { st.ShiftNext(); return(OperatorCode.Nand); } else if (next == '|') { st.ShiftNext(); return(OperatorCode.Nor); } return(OperatorCode.Not); case '<': if (next == '=') { st.ShiftNext(); return(OperatorCode.LessEqual); } else if (next == '<') { st.ShiftNext(); return(OperatorCode.LeftShift); } return(OperatorCode.Less); case '>': if (next == '=') { st.ShiftNext(); return(OperatorCode.GreaterEqual); } else if (next == '>') { st.ShiftNext(); return(OperatorCode.RightShift); } return(OperatorCode.Greater); case '|': if (next == '|') { st.ShiftNext(); return(OperatorCode.Or); } return(OperatorCode.BitOr); case '&': if (next == '&') { st.ShiftNext(); return(OperatorCode.And); } return(OperatorCode.BitAnd); case '^': if (next == '^') { st.ShiftNext(); return(OperatorCode.Xor); } return(OperatorCode.BitXor); case '~': return(OperatorCode.BitNot); case '?': return(OperatorCode.Ternary_a); case '#': return(OperatorCode.Ternary_b); } throw new CodeEE("'" + cur + "'は演算子として認識できません"); }
/// <summary> /// 字句解析・構文解析用。ホワイトスペースの他、コメントも飛ばす。 /// </summary> public static int SkipWhiteSpace(StringStream st) { int count = 0; while (true) { switch (st.Current) { case ' ': case '\t': count++; st.ShiftNext(); continue; case ' ': if (!Config.SystemAllowFullSpace) return count; //throw new CodeEE("予期しない全角スペースを発見しました"); goto case ' '; case ';': if (st.CurrentEqualTo(";#;") && Program.DebugMode) { st.Jump(3); continue; } else if (st.CurrentEqualTo(";!;")) { st.Jump(3); continue; } st.Seek(0, System.IO.SeekOrigin.End); return count; } return count; } }
/// <summary> /// endWithが見つかるまで読み込む。始点と終端のチェックは呼び出し側で行うこと。 /// エスケープあり。 /// </summary> /// <param name="st"></param> /// <returns></returns> public static string ReadString(StringStream st, StrEndWith endWith) { StringBuilder buffer = new StringBuilder(100); while (true) { switch (st.Current) { case '\0': goto end; case '\"': if (endWith == StrEndWith.DoubleQuotation) goto end; break; case ',': if ((endWith == StrEndWith.Comma) || (endWith == StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon)) goto end; break; case '(': case '[': case ';': if (endWith == StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon) goto end; break; case '\\'://エスケープ処理 st.ShiftNext();//\を読み飛ばす switch (st.Current) { case StringStream.EndOfString: throw new CodeEE("エスケープ文字\\の後に文字がありません"); case '\n': break; case 's': buffer.Append(' '); break; case 'S': buffer.Append(' '); break; case 't': buffer.Append('\t'); break; case 'n': buffer.Append('\n'); break; default: buffer.Append(st.Current); break; } st.ShiftNext();//\の次の文字を読み飛ばす continue; } buffer.Append(st.Current); st.ShiftNext(); } end: return buffer.ToString(); }
/// <summary> /// 字句分割 /// "[1] あ [2] いうえ "を"[1]"," ", "あ"," ","[2]"," ","いうえ"," "に分割 /// </summary> /// <param name="st"></param> /// <returns></returns> private static List<string> lex(StringStream st) { List<string> strs = new List<string>(); int state = 0; int startIndex = 0; VoidMethod reduce = delegate { if (st.CurrentPosition == startIndex) return; int length = st.CurrentPosition - startIndex; strs.Add(st.Substring(startIndex, length)); startIndex = st.CurrentPosition; }; while (!st.EOS) { if (st.Current == '[') { if (state == 1)//"["内部 goto unanalyzable; reduce(); state = 1; st.ShiftNext(); } else if (st.Current == ']') { if (state != 1)//"["外部 goto unanalyzable; st.ShiftNext(); reduce(); state = 0; } else if ((state == 0) && (LexicalAnalyzer.IsWhiteSpace(st.Current))) { reduce(); LexicalAnalyzer.SkipAllSpace(st); reduce(); } else { st.ShiftNext(); } } reduce(); return strs; unanalyzable: return null; }
/// <summary> /// 解析できるものは関数宣言や式のみ。FORM文字列や普通の文字列を送ってはいけない /// return時にはendWithの文字がCurrentになっているはず。終端の適切さの検証は呼び出し元が行う。 /// </summary> /// <returns></returns> public static WordCollection Analyse(StringStream st, LexEndWith endWith, LexAnalyzeFlag flag) { WordCollection ret = new WordCollection(); int nestBracketS = 0; //int nestBracketM = 0; int nestBracketL = 0; while (true) { switch (st.Current) { case '\n': case '\0': goto end; case ' ': case '\t': st.ShiftNext(); continue; case ' ': if (!Config.SystemAllowFullSpace) { throw new CodeEE("字句解析中に予期しない全角スペースを発見しました(この警告はシステムオプション「" + Config.GetConfigName(ConfigCode.SystemAllowFullSpace) + "」により無視できます)"); } st.ShiftNext(); continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ret.Add(new LiteralIntegerWord(ReadInt64(st, false))); break; case '>': if (endWith == LexEndWith.GreaterThan) { goto end; } goto case '+'; case '+': case '-': case '*': case '/': case '%': case '=': case '!': case '<': case '|': case '&': case '^': case '~': case '?': case '#': if ((nestBracketS == 0) && (nestBracketL == 0)) { if (endWith == LexEndWith.Operator) { goto end; //代入演算子のはずである。呼び出し元がチェックするはず } else if ((endWith == LexEndWith.Percent) && (st.Current == '%')) { goto end; } else if ((endWith == LexEndWith.Question) && (st.Current == '?')) { goto end; } } ret.Add(new OperatorWord(ReadOperator(st, (flag & LexAnalyzeFlag.AllowAssignment) == LexAnalyzeFlag.AllowAssignment))); break; case ')': ret.Add(new SymbolWord(')')); nestBracketS--; st.ShiftNext(); continue; case ']': ret.Add(new SymbolWord(']')); nestBracketL--; st.ShiftNext(); continue; case '(': ret.Add(new SymbolWord('(')); nestBracketS++; st.ShiftNext(); continue; case '[': if (st.Next == '[') { //throw new CodeEE("字句解析中に予期しない文字'[['を発見しました"); ////1808alpha006 rename処理変更 //1808beta009 ここだけ戻す //現在の処理だとここに来た時点でrename失敗確定だが警告内容を元に戻すため if (ParserMediator.RenameDic == null) { throw new CodeEE("字句解析中に予期しない文字\"[[\"を発見しました"); } int start = st.CurrentPosition; int find = st.Find("]]"); if (find <= 2) { if (find == 2) { throw new CodeEE("空の[[]]です"); } else { throw new CodeEE("対応する\"]]\"のない\"[[\"です"); } } string key = st.Substring(start, find + 2); //1810 ここまでで置換できなかったものは強制エラーにする //行連結前に置換不能で行連結より置換することができるようになったものまで置換されていたため throw new CodeEE("字句解析中に置換(rename)できない符号" + key + "を発見しました"); //string value = null; //if (!ParserMediator.RenameDic.TryGetValue(key, out value)) // throw new CodeEE("字句解析中に置換(rename)できない符号" + key + "を発見しました"); //st.Replace(start, find + 2, value); //continue;//その場から再度解析スタート } ret.Add(new SymbolWord('[')); nestBracketL++; st.ShiftNext(); continue; case ':': ret.Add(new SymbolWord(':')); st.ShiftNext(); continue; case ',': if ((endWith == LexEndWith.Comma) && (nestBracketS == 0)) // && (nestBracketL == 0)) { goto end; } ret.Add(new SymbolWord(',')); st.ShiftNext(); continue; //case '}': ret.Add(new SymbolWT('}')); nestBracketM--; continue; //case '{': ret.Add(new SymbolWT('{')); nestBracketM++; continue; case '\'': if ((flag & LexAnalyzeFlag.AllowSingleQuotationStr) == LexAnalyzeFlag.AllowSingleQuotationStr) { st.ShiftNext(); ret.Add(new LiteralStringWord(ReadString(st, StrEndWith.SingleQuotation))); if (st.Current != '\'') { throw new CodeEE("\'が閉じられていません"); } st.ShiftNext(); break; } if ((flag & LexAnalyzeFlag.AnalyzePrintV) != LexAnalyzeFlag.AnalyzePrintV) { //AssignmentStr用特殊処理 代入文の代入演算子を探索中で'=の場合のみ許可 if ((endWith == LexEndWith.Operator) && (nestBracketS == 0) && (nestBracketL == 0) && st.Next == '=') { goto end; } throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました"); } st.ShiftNext(); ret.Add(new LiteralStringWord(ReadString(st, StrEndWith.Comma))); if (st.Current == ',') { goto case ','; //続きがあるなら,の処理へ。それ以外は行終端のはず } goto end; case '}': if (endWith == LexEndWith.RightCurlyBrace) { goto end; } throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました"); case '\"': st.ShiftNext(); ret.Add(new LiteralStringWord(ReadString(st, StrEndWith.DoubleQuotation))); if (st.Current != '\"') { throw new CodeEE("\"が閉じられていません"); } st.ShiftNext(); break; case '@': if (st.Next != '\"') { ret.Add(new SymbolWord('@')); st.ShiftNext(); continue; } st.ShiftNext(); st.ShiftNext(); ret.Add(AnalyseFormattedString(st, FormStrEndWith.DoubleQuotation, false)); if (st.Current != '\"') { throw new CodeEE("\"が閉じられていません"); } st.ShiftNext(); break; case '.': ret.Add(new SymbolWord('.')); st.ShiftNext(); continue; case '\\': if (st.Next != '@') { throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました"); } { st.Jump(2); ret.Add(new StrFormWord(new string[] { "", "" }, new SubWord[] { AnalyseYenAt(st) })); } break; case '{': case '$': throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました"); case ';': //1807 行中コメント if (st.CurrentEqualTo(";#;") && Program.DebugMode) { st.Jump(3); break; } else if (st.CurrentEqualTo(";!;")) { st.Jump(3); break; } st.Seek(0, System.IO.SeekOrigin.End); goto end; default: { ret.Add(new IdentifierWord(ReadSingleIdentifier(st))); break; } } } end: if ((nestBracketS != 0) || (nestBracketL != 0)) { if (nestBracketS < 0) { throw new CodeEE("字句解析中に対応する'('のない')'を発見しました"); } else if (nestBracketS > 0) { throw new CodeEE("字句解析中に対応する')'のない'('を発見しました"); } if (nestBracketL < 0) { throw new CodeEE("字句解析中に対応する'['のない']'を発見しました"); } else if (nestBracketL > 0) { throw new CodeEE("字句解析中に対応する']'のない'['を発見しました"); } } if (UseMacro) { return(expandMacro(ret)); } return(ret); }
/// <summary> /// Consoleの文字表示用。字句解析や構文解析に使ってはならない /// </summary> public static int SkipAllSpace(StringStream st) { int count = 0; while (true) { switch (st.Current) { case ' ': case '\t': case ' ': count++; st.ShiftNext(); continue; } return count; } }