/// <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> /// 解析できるものは関数宣言や式のみ。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); }
//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 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> /// 解析できるものは関数宣言や式のみ。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> /// 単語を文字列で取得。マクロ適用なし /// </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)); }
//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> /// 字句分割 /// "[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; }