Exemplo n.º 1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="cs"></param>
        public ActorScriptSection(CustomSection cs)
        {
            var stream           = new MemoryStream((byte[])cs.Content);
            var reader           = new Reader(stream);
            var previousSection  = ActorScriptSubsection.Labels;
            var preSectionOffset = reader.Offset;

            while (reader.TryReadVarUInt7(out var id)) //At points where TryRead is used, the stream can safely end.
            {
                if (id != 0 && (ActorScriptSubsection)id < previousSection)
                {
                    throw new ModuleLoadException($"Sections out of order; section {(ActorScriptSubsection)id} encounterd after {previousSection}.", preSectionOffset);
                }
                var payloadLength = reader.ReadVarUInt32();

                switch ((ActorScriptSubsection)id)
                {
                case ActorScriptSubsection.Labels:
                {
                    var count = reader.ReadVarUInt32();
                    Labels = new LabelMap((int)count);
                    for (int i = 0; i < count; i++)
                    {
                        var index      = reader.ReadVarUInt32();
                        var nameLength = reader.ReadVarUInt32();
                        var name       = reader.ReadString(nameLength);
                        Labels.Add(index, name);
                    }
                }
                break;
                }

                previousSection = (ActorScriptSubsection)id;
            }
        }
Exemplo n.º 2
0
        public void CanLogBytes()
        {
            _labels.Add(new Label("Start", 0x1000));
            _labels.Add(new Label("MySubroutine", 0x1012));

            ushort address = 0x1000;
            ushort size    = 50;
            var    bytes   = _addressMap.ReadBlock(address, (ushort)(address + size - 1));

            _logFormatter.LogBytes(address, bytes);
            var output = _logFormatter.ToString();

            Console.WriteLine(""); // Clear the hanging line
            Debug.WriteLine(output);
            Console.WriteLine(output);
            Assert.IsTrue(output.Contains("[1012] MySubroutine:"));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Adjusts the label map so that only local variables start with an underscore ('_').
        /// This is necessary for assemblers like 64tass that use a leading underscore to
        /// indicate that a label should be local.
        ///
        /// This may be called even if label localization is disabled.  In that case we just
        /// create an empty label map and populate as needed.
        ///
        /// Only call this if underscores are used to indicate local labels.
        /// </summary>
        public void MaskLeadingUnderscores()
        {
            bool allGlobal = false;

            if (LabelMap == null)
            {
                allGlobal = true;
                LabelMap  = new Dictionary <string, string>();
            }

            // Throw out the original local label generation.
            LabelMap.Clear();

            // Use this to test for uniqueness.  We add all labels here as we go, not just the
            // ones being remapped.  For each label we either add the original or the localized
            // form.
            SortedList <string, string> allLabels = new SortedList <string, string>();

            for (int i = 0; i < mProject.FileDataLength; i++)
            {
                Symbol sym = mProject.GetAnattrib(i).Symbol;
                if (sym == null)
                {
                    // No label at this offset.
                    continue;
                }

                string newLabel;
                if (allGlobal || mGlobalFlags[i])
                {
                    // Global symbol.  Don't let it start with '_'.
                    if (sym.Label.StartsWith("_"))
                    {
                        // There's an underscore here that was added by the user.  Stick some
                        // other character in front.
                        newLabel = "X" + sym.Label;
                    }
                    else
                    {
                        // No change needed.
                        newLabel = sym.Label;
                    }
                }
                else
                {
                    // Local symbol.
                    if (sym.Label.StartsWith("_"))
                    {
                        // The original starts with one or more underscores.  Adding another
                        // will create a "__" label, which is reserved in 64tass.
                        newLabel = "_X" + sym.Label;
                    }
                    else
                    {
                        newLabel = "_" + sym.Label;
                    }
                }

                // Make sure it's unique.
                string uniqueLabel = newLabel;
                int    uval        = 1;
                while (allLabels.ContainsKey(uniqueLabel))
                {
                    uniqueLabel = newLabel + uval.ToString();
                }
                allLabels.Add(uniqueLabel, uniqueLabel);

                // If it's different, add it to the label map.
                if (sym.Label != uniqueLabel)
                {
                    LabelMap.Add(sym.Label, uniqueLabel);
                }
            }

            Debug.WriteLine("UMAP: allcount=" + allLabels.Count + " mapcount=" + LabelMap.Count);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Remaps labels that match opcode names.  Updated names will be added to LabelMap.
        /// This should be run after localization and underscore concealment have finished.
        /// </summary>
        /// <remarks>
        /// Most assemblers don't like it if you create a label with the same name as an
        /// opcode, e.g. "jmp LSR" doesn't work.  We can use the label map to work around
        /// the issue.
        ///
        /// Most assemblers regard mnemonics as case-insensitive, even if labels are
        /// case-sensitive, so we want to remap both "lsr" and "LSR".
        ///
        /// This doesn't really have anything to do with label localization other than that
        /// we're updating the label remap table.
        /// </remarks>
        public void FixOpcodeLabels()
        {
            if (LabelMap == null)
            {
                LabelMap = new Dictionary <string, string>();
            }

            // Create a searchable list of opcode names using the current CPU definition.
            // (All tested assemblers that failed on opcode names only did so for names
            // that were part of the current definition, e.g. "TSB" was accepted as a label
            // when the CPU was set to 6502.)
            Dictionary <string, Asm65.OpDef> opnames = new Dictionary <string, Asm65.OpDef>();

            Asm65.CpuDef cpuDef = mProject.CpuDef;
            for (int i = 0; i < 256; i++)
            {
                Asm65.OpDef op = cpuDef.GetOpDef(i);
                // There may be multiple entries with the same name (e.g. "NOP").  That's fine.
                opnames[op.Mnemonic.ToUpperInvariant()] = op;
            }

            // Create a list of all labels, for uniqueness testing.  If a label has been
            // remapped, we add the remapped entry.
            // (All tested assemblers that failed on opcode names only did so for names
            // in their non-localized form.  While "LSR" failed, "@LSR", "_LSR", ".LSR", etc.
            // were accepted.  So if it  was remapped by the localizer, we don't need to
            // worry about it.)
            SortedList <string, string> allLabels = new SortedList <string, string>();

            for (int i = 0; i < mProject.FileDataLength; i++)
            {
                Symbol sym = mProject.GetAnattrib(i).Symbol;
                if (sym == null)
                {
                    continue;
                }
                LabelMap.TryGetValue(sym.Label, out string mapLabel);
                if (mapLabel != null)
                {
                    allLabels.Add(mapLabel, mapLabel);
                }
                else
                {
                    allLabels.Add(sym.Label, sym.Label);
                }
            }

            // Now run through the list of labels, looking for any that match opcode
            // mnemonics.
            for (int i = 0; i < mProject.FileDataLength; i++)
            {
                Symbol sym = mProject.GetAnattrib(i).Symbol;
                if (sym == null)
                {
                    // No label at this offset.
                    continue;
                }
                string cmpLabel = sym.Label;
                if (LabelMap.TryGetValue(sym.Label, out string mapLabel))
                {
                    cmpLabel = mapLabel;
                }

                if (opnames.ContainsKey(cmpLabel.ToUpperInvariant()))
                {
                    //Debug.WriteLine("Remapping label (op mnemonic): " + sym.Label);

                    int    uval = 0;
                    string uniqueLabel;
                    do
                    {
                        uval++;
                        uniqueLabel = cmpLabel + "_" + uval.ToString();
                    } while (allLabels.ContainsKey(uniqueLabel));

                    allLabels.Add(uniqueLabel, uniqueLabel);
                    LabelMap.Add(sym.Label, uniqueLabel);
                }
            }

            if (LabelMap.Count == 0)
            {
                // didn't do anything, lose the table
                LabelMap = null;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// スクリプトコードを構文解析して,実行可能
        /// </summary>
        /// <returns>The parse.</returns>
        /// <param name="code">Code.</param>
        /// <param name="echoCommand">Echo command.</param>
        public static INCode Parse(string code, string echoCommand = "say")
        {
            // スクリプトをステートメントに区切る
            var statements = code.SplitLine();

            // 汎用文字列バッファ
            var buffer = new StringBuilder();

            // 文字列リテラルかどうか
            var isQuotation = false;

            // 解析用トークン
            var token = Token.SpriteTag;

            // 一時保存変数の定義
            string spTag, comName;
            var    args = new List <string>();

            // ステートメント
            var statementList = new List <INStatement>();

            // ラベル一覧
            var labels = new LabelMap();

            // 行番号
            var line = 0;

            foreach (var statement in statements)
            {
                // 一時保存変数やフラグの初期化
                spTag = comName = "";
                args?.Clear();
                token       = Token.SpriteTag;
                isQuotation = false;

                // ここからステートメントの解析
                for (var i = 0; i < statement.Length; i++)
                {
                    // 現在パースしている文字
                    var chr = statement[i];
                    // chrの1つ前またはnull文字
                    var cm1 = (i > 0) ? statement[i - 1] : '\0';
                    // chrの1つ後またはnull文字
                    var cp1 = (i < statement.Length - 1) ? statement[i + 1] : '\0';

                    // リテラル外において,空白などは無視される
                    if ((!isQuotation) && (char.IsControl(chr) || char.IsSeparator(chr) || char.IsWhiteSpace(chr)))
                    {
                        continue;
                    }

                    // コメント文
                    if ((!isQuotation) && chr == '/' && cp1 == '/')
                    {
                        break;
                    }

                    // 解析処理
                    switch (token)
                    {
                    // スプライトタグ
                    case Token.SpriteTag:
                        // 現在地がプレフィックスであれば抜ける
                        if (chr == COMMAND_PREFIX || chr == MESSAGE_PREFIX || chr == LABEL_PREFIX)
                        {
                            // スプライトタグをバッファの文字列に設定する
                            spTag = buffer.ToString();

                            // トークンの切り替え
                            token = Token.Prefix;

                            // バッファの掃除
                            buffer.Clear();

                            // 次の段階でプレフィックスのチェックをするためiを前にずらす (for文によるiの増加に合わせる)
                            i--;

                            // 次にすっ飛ばす
                            continue;
                        }

                        //読み取った文字をバッファに入れる
                        buffer.Append(chr);
                        break;

                    // プレフィックスの解析
                    case Token.Prefix:
                        switch (chr)
                        {
                        case COMMAND_PREFIX:
                            // コマンドの解析に飛ぶ
                            token = Token.Name;
                            continue;

                        case MESSAGE_PREFIX:
                            // メッセージコマンドということにして
                            comName = echoCommand;
                            // 引数解析にすっ飛ばす
                            token = Token.Arguments;
                            continue;

                        case LABEL_PREFIX:
                            // コマンドではない処理を行う
                            token = Token.LabelName;
                            continue;

                        default:
                            throw new ParseStatementException($"Invalid prefix {(chr != '\0' ? chr.ToString() : "")}", line, i);
                        }

                    // コマンド名の解析
                    case Token.Name:
                        //読み取った文字をバッファに入れる
                        buffer.Append(chr);

                        // 区切り文字が登場したら
                        if (cp1 == COMMAND_SEPARATOR)
                        {
                            // コマンド名を設定して
                            comName = buffer.ToString();
                            // バッファをお掃除して
                            buffer.Clear();
                            // 区切り文字の分カーソルを進めて
                            i++;
                            // トークンを切り替えて
                            token = Token.Arguments;
                            // イッテヨシ
                            continue;
                        }
                        break;

                    // 引数の構文解析
                    case Token.Arguments:

                        switch (chr)
                        {
                        // エスケープシーケンスの処理
                        case '\\':
                            switch (cp1)
                            {
                            // 改行
                            case 'n':
                                buffer = buffer.Append('\n');
                                break;

                            // ダブルクォート
                            case '"':
                                buffer = buffer.Append('"');
                                break;

                            // バックスラッシュ
                            case '\\':
                                buffer = buffer.Append('\\');
                                break;

                            // 予期しないやつ
                            default:
                                throw new ParseStatementException($@"Invalid escape sequence \{(cp1 != '\0' ? cp1.ToString() : "")}", line, i);
                            }
                            // エスケープ文字分飛ばす
                            i++;
                            break;

                        // ダブルクォート
                        case '"':
                            // ダブルクォートで包んだ文字列は,空白や,の影響を受けない
                            isQuotation = !isQuotation;
                            break;

                        // その他の文字
                        default:
                            // 引数の区切り
                            if ((chr == ',' && !isQuotation))
                            {
                                args?.Add(buffer.ToString());
                                buffer.Clear();
                            }
                            // 読み取った引数の文字をバッファに入れる
                            else
                            {
                                buffer.Append(chr);
                            }
                            break;
                        }
                        break;

                    // ラベル名
                    case Token.LabelName:
                        // 念のためステートメントとして登録できないようコマンド名を初期化
                        comName = "";
                        buffer.Append(chr);

                        break;

                    // 異常なトークン(プログラムのバグでない限りありえない)
                    default:
                        throw new ParseStatementException($@"(Bug!!) Unknown token ""{token}""", line, i);
                    }
                }

                // バッファが空でない場合,データが残っているので加味
                if (!string.IsNullOrEmpty(buffer.ToString()))
                {
                    switch (token)
                    {
                    case Token.Name:
                        comName = buffer.ToString();
                        break;

                    case Token.LabelName:
                        labels.Add(buffer.ToString(), line);
                        break;

                    default:
                        args.Add(buffer.ToString());
                        break;
                    }

                    buffer.Clear();
                }

                // コマンド名がカラッポ = ラベルやコメント行や空行なのでスルー
                if (string.IsNullOrEmpty(comName))
                {
                    continue;
                }

                statementList.Add(new NStatement(comName, spTag, args.ToArray()));

                line++;
            }
            return(new NCode(labels, statementList.ToArray()));
        }