/// <summary> /// \@直後からの開始、\@の直後がCurrentになる /// </summary> /// <param name="st"></param> /// <returns></returns> public static YenAtSubWord AnalyseYenAt(StringStream st) { WordCollection w = Analyse(st, LexEndWith.Question, LexAnalyzeFlag.None); 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> /// 単語を文字列で取得。マクロ適用なし /// </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; var 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("予期しない全角スペースを発見しました(この警告はシステムオプション「" + Config.GetConfigName(ConfigCode.SystemAllowFullSpace) + "」により無視できます)"); } goto end; } st.ShiftNext(); } end: return(st.Substring(start, st.CurrentPosition - start)); }
/// <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> /// 字句解析・構文解析用。文字列直前の半角スペースを飛ばす。性質上、半角スペースのみを見る。 /// </summary> public static int SkipHalfSpace(StringStream st) { int count = 0; while (st.Current == ' ') { count++; st.ShiftNext(); } 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> /// 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> /// 字句解析・構文解析用。ホワイトスペースの他、コメントも飛ばす。 /// </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); } }
private void loadCharacterDataFile(string csvPath, string csvName, bool disp) { CharacterTemplate tmpl = null; EraStreamReader eReader = new EraStreamReader(); if (!eReader.Open(csvPath, csvName)) { output.PrintError(eReader.Filename + "のオープンに失敗しました"); return; } ScriptPosition position = null; if (disp) output.PrintLine(eReader.Filename + "読み込み中・・・"); try { Int64 index = -1; StringStream st = null; while ((st = eReader.ReadEnabledLine()) != null) { position = new ScriptPosition(eReader.Filename, eReader.LineNo, st.RowString); string[] tokens = st.Substring().Split(','); if (tokens.Length < 2) { ParserMediator.Warn("\",\"が必要です", position, 1); continue; } if (tokens[0].Length == 0) { ParserMediator.Warn("\",\"で始まっています", position, 1); continue; } if ((tokens[0].Equals("NO", Config.SCVariable)) || (tokens[0].Equals("番号", Config.SCVariable))) { if (tmpl != null) { ParserMediator.Warn("番号が二重に定義されました", position, 1); continue; } if (!Int64.TryParse(tokens[1].TrimEnd(), out index)) { ParserMediator.Warn(tokens[1] + "を整数値に変換できません", position, 1); continue; } tmpl = new CharacterTemplate(index, this); string no = eReader.Filename.ToUpper(); no = no.Substring(no.IndexOf("CHARA") + 5); StringBuilder sb = new StringBuilder(); StringStream ss = new StringStream(no); while (!ss.EOS && char.IsDigit(ss.Current)) { sb.Append(ss.Current); ss.ShiftNext(); } if (sb.Length > 0) tmpl.csvNo = Convert.ToInt64(sb.ToString()); else tmpl.csvNo = 0; //tmpl.csvNo = index; CharacterTmplList.Add(tmpl); continue; } if (tmpl == null) { ParserMediator.Warn("番号が定義される前に他のデータが始まりました", position, 1); continue; } toCharacterTemplate(gamebase, position, tmpl, tokens); } } catch { System.Media.SystemSounds.Hand.Play(); if (position != null) ParserMediator.Warn("予期しないエラーが発生しました", position, 3); else output.PrintError("予期しないエラーが発生しました"); return; } finally { eReader.Dispose(); } }
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); } }
private bool tryToInt64(string str, out Int64 p) { p = -1; if (string.IsNullOrEmpty(str)) return false; StringStream st = new StringStream(str); int sign = 1; if (st.Current == '+') st.ShiftNext(); else if (st.Current == '-') { sign = -1; st.ShiftNext(); } //1803beta005 char.IsDigitは全角数字とかまでひろってしまうので・・・ //if (!char.IsDigit(st.Current)) // return false; switch (st.Current) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: return false; } try { p = LexicalAnalyzer.ReadInt64(st, false); p = p * sign; } catch { return false; } return true; }
/// <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); }
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); }
string parseInput(StringStream st, bool isNest) { StringBuilder sb = new StringBuilder(20); StringBuilder num = new StringBuilder(20); int res = 0; while (!st.EOS && (!isNest || st.Current != ')')) { if (st.Current == '(') { st.ShiftNext(); string tstr = parseInput(st, true); if (!st.EOS) { st.ShiftNext(); if (st.Current == '*') { st.ShiftNext(); while (char.IsNumber(st.Current)) { num.Append(st.Current); st.ShiftNext(); } if (num.ToString() != "" && num.ToString() != null) { int.TryParse(num.ToString(), out res); for (int i = 0; i < res; i++) sb.Append(tstr); num.Remove(0, num.Length); } } else sb.Append(tstr); continue; } else { sb.Append(tstr); break; } } else if (st.Current == '\\') { st.ShiftNext(); switch (st.Current) { case 'n': sb.Append('\n'); break; case 'r': sb.Append('\r'); break; case 'e': sb.Append("\\e"); break; case '\n': break; default: sb.Append(st.Current); break; } } else sb.Append(st.Current); st.ShiftNext(); } return sb.ToString(); }
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); }
//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> /// 失敗したら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> /// 失敗したら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> /// <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); }
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> /// 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> /// 失敗したら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; }
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; }
//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 override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state) { //int termnum = 0; //foreach (IOperandTerm term in ((ExpressionArrayArgument)func.Argument).TermList) //{ // string arg = term.GetStrValue(exm); // StringStream aSt = new StringStream(arg); // WordCollection wc = LexicalAnalyzer.Analyse(aSt, LexEndWith.EoL, false, false); // exm.VEvaluator.SetResultX((ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL).GetIntValue(exm)), termnum); // termnum++; //} //state.Return(exm.VEvaluator.RESULT); //if (state.ScriptEnd) // return; //int termnum = 0; StringStream aSt = new StringStream(((ExpressionArgument)func.Argument).Term.GetStrValue(exm)); List<long> termList = new List<long>(); while (!aSt.EOS) { WordCollection wc = LexicalAnalyzer.Analyse(aSt, LexEndWith.Comma, false, false); //exm.VEvaluator.SetResultX(ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL).GetIntValue(exm), termnum++); termList.Add(ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL).GetIntValue(exm)); aSt.ShiftNext(); LexicalAnalyzer.SkipHalfSpace(aSt); //termnum++; } if (termList.Count == 0) termList.Add(0); exm.VEvaluator.SetResultX(termList); state.Return(exm.VEvaluator.RESULT); if (state.ScriptEnd) return; }
/// <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> /// @"などの直後からの開始 /// 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 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> /// 解析できるものは関数宣言や式のみ。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; }
/// <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); }
/// <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> /// 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> /// 失敗したら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); }
/// <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> /// 字句解析・構文解析用。文字列直前の半角スペースを飛ばす。性質上、半角スペースのみを見る。 /// </summary> public static int SkipHalfSpace(StringStream st) { int count = 0; while (st.Current == ' ') { count++; st.ShiftNext(); } return count; }
/// <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> /// 解析できるものは関数宣言や式のみ。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); }
private bool tryatoi(string str, out Int64 i) { if (Int64.TryParse(str, out i)) return true; StringStream st = new StringStream(str); StringBuilder sb = new StringBuilder(str.Length); while (true) { if (st.EOS) break; if (!char.IsNumber(st.Current)) break; sb.Append(st.Current); st.ShiftNext(); } if (sb.Length > 0) if (Int64.TryParse(sb.ToString(), out i)) return true; return false; }