/// <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); } }
/// <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> /// 解析できるものは関数宣言や式のみ。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> 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; } }
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); } }