예제 #1
0
        private bool ParsePragma(int lineIndex, string line, string opcode, List <string> tokens, ParserState state)
        {
            string pragma = opcode.ToLowerInvariant();

            if (!LineSearch.MatchPragma(pragma))
            {
                return(false);
            }

            switch (pragma)
            {
            case ".dat8":
                ParseData8(line.Replace(".dat8", string.Empty).Trim(), state);
                return(true);

            case ".dat16":
                ParseData16(line.Replace(".dat16", string.Empty).Trim(), state);
                return(true);

            case ".advance":

                break;

            case ".alias":
            {
                int value;
                if (tokens.Count != 3)
                {
                    throw new Exception("alias pragma takes two parameters");
                }
                string alias = tokens[1];
                if (!char.IsLetter(alias[0]))
                {
                    throw new Exception("alias must begin with a letter");
                }
                if (alias.Any(t => !char.IsLetterOrDigit(t)))
                {
                    throw new Exception("alias must be composed of letters and digits");
                }

                tokens[2] = tokens[2].Replace("$", "0x");
                object convertFromString = new Int32Converter().ConvertFromString(tokens[2]);
                if (convertFromString != null)
                {
                    value = (int)convertFromString;
                }
                else
                {
                    throw new Exception("alias pragma - ushort parameter must be an unsigned 16-bit integer");
                }

                Scopes.Scope scope = state.Scopes.GetLastOpenScope();
                scope.AddAlias(alias, (ushort)value);

                return(true);
            }

            case ".alignglobals":
            {
                int value;
                if (tokens.Count != 2)
                {
                    throw new Exception("alignglobals pragma takes a single parameter");
                }
                if (!int.TryParse(tokens[1], out value))
                {
                    throw new Exception("alignglobals pragma parameter must be an integer");
                }
                if (value < 1 || value > 4)
                {
                    throw new Exception("alignglobals pragma parameter must be an integer between 1 and 4");
                }
                m_Alignment = value;
                return(true);
            }

            case ".checkpc":

                break;

            case ".org":

                break;

            case ".incbin":
                return(IncludeBinary(tokens, state));

            case ".include":
                return(IncludeAsm(tokens, state));

            case ".macro":

                break;

            case ".macend":

                break;

            case ".require":

                break;

            case ".reserve":

                break;

            case ".scope":
            case "{":
                state.Scopes.ScopeOpen(state.Code.Count, lineIndex);
                return(true);

            case ".scend":
            case "}":
                return(state.Scopes.ScopeClose(state.Code.Count));
            }

            throw new Exception($"Unimplemented pragma in line {line}");
        }
예제 #2
0
        private void AssembleLine(int lineIndex, string line, ParserState state)
        {
            line = line.Trim();

            if (LineSearch.MatchLabel(line))
            {
                if (!state.Scopes.IsScopeOpen) // global scope
                {
                    while ((state.Code.Count % m_Alignment) != 0)
                    {
                        state.Code.Add(0x00);
                    }
                }

                // parse label and determine if there is anything else to parse on this line.
                int remaiderLineContentIndex = ParseLabel(line, state);
                if (remaiderLineContentIndex <= 0)
                {
                    return;
                }
                // if there is something left to parse, trim it and then interpret it as its own line.
                line = line.Remove(0, remaiderLineContentIndex).Trim();
                if (line.Length == 0)
                {
                    return;
                }
            }

            List <string> tokens = Tokenize(line);
            string        opcode = tokens[0];

            opcode = opcode.Trim();

            if (ParsePragma(lineIndex, line, opcode, tokens, state))
            {
                // Successfully parsed a pragma, no need to continue with this line.
                return;
            }

            OpcodeFlag opcodeFlag = OpcodeFlag.BitWidth16; // default to operating on 16 bits

            // Look for flags on operands (xxx.yyy, where y is the flag).
            if (opcode.IndexOf('.') != -1 && (opcode.IndexOf('.') > 1) && (opcode.Length - opcode.IndexOf('.') - 1 > 0))
            {
                // opcode has a flag
                string flag = opcode.Substring(opcode.IndexOf('.') + 1);
                if (!ParseOpcodeFlag(flag, ref opcodeFlag))
                {
                    throw new Exception($"Unknown bit width flag '{flag}' for instruction '{line}'");
                }
                opcode = opcode.Substring(0, opcode.IndexOf('.'));
            }

            // get the assembler for this opcode. If no assembler exists, throw error.
            Func <List <string>, OpcodeFlag, ParserState, List <ushort> > assembler;

            if (m_Opcodes.ContainsKey(opcode.ToLowerInvariant()))
            {
                assembler = m_Opcodes[opcode.ToLowerInvariant()];
            }
            else
            {
                throw new Exception($"Undefined instruction in line \"{line}\"");
            }

            // get the parameters
            List <string> param = new List <string>();

            for (int i = 1; i < tokens.Count; i++)
            {
                param.Add(tokens[i].Trim());
            }

            // pass the params to the opcode's assembler. If no output, throw error.
            List <ushort> code = assembler(param, opcodeFlag, state);

            if (code == null)
            {
                throw new Exception($"Error assembling line {line}");
            }

            // add the output of the assembler to the machine code output.
            for (int i = 0; i < code.Count; i++)
            {
                ushort this_opcode = code[i];
                state.Code.Add((byte)(this_opcode & 0x00ff));
                state.Code.Add((byte)((this_opcode & 0xff00) >> 8));
            }
        }