feat(core/asm): add assembler token, operand, and statement primitives
This commit is contained in:
1 parent
8c516cccbf
commit
77e45f92f6
4 files changed
+212
No files matched your search
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Chip8.Core.Assembly;
|
||||||
|
|
||||||
|
public sealed class AsmException : Exception
|
||||||
|
{
|
||||||
|
public AsmException(string message, SourcePosition position)
|
||||||
|
: base("assembly error at " + position + ": " + message)
|
||||||
|
{
|
||||||
|
this.reason = message;
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string reason { get; }
|
||||||
|
public SourcePosition position { get; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Chip8.Core.Assembly;
|
||||||
|
|
||||||
|
public enum OperandKind
|
||||||
|
{
|
||||||
|
Register,
|
||||||
|
RegisterRange,
|
||||||
|
Immediate,
|
||||||
|
IndexRegister,
|
||||||
|
IndexIndirect,
|
||||||
|
DelayTimer,
|
||||||
|
SoundTimer,
|
||||||
|
KeyReg,
|
||||||
|
FontReg,
|
||||||
|
BigFontReg,
|
||||||
|
BcdReg,
|
||||||
|
RplReg,
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class Operand
|
||||||
|
{
|
||||||
|
Operand(OperandKind kind, SourcePosition position)
|
||||||
|
{
|
||||||
|
this.kind = kind;
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperandKind kind { get; }
|
||||||
|
public SourcePosition position { get; }
|
||||||
|
public int registerIndex { get; private init; }
|
||||||
|
public int rangeEnd { get; private init; }
|
||||||
|
public IReadOnlyList<Token> expressionTokens { get; private init; } = System.Array.Empty<Token>();
|
||||||
|
|
||||||
|
public static Operand register(int index, SourcePosition position) =>
|
||||||
|
new(OperandKind.Register, position) { registerIndex = index };
|
||||||
|
|
||||||
|
public static Operand registerRange(int start, int end, SourcePosition position) =>
|
||||||
|
new(OperandKind.RegisterRange, position) { registerIndex = start, rangeEnd = end };
|
||||||
|
|
||||||
|
public static Operand immediate(IReadOnlyList<Token> tokens, SourcePosition position) =>
|
||||||
|
new(OperandKind.Immediate, position) { expressionTokens = tokens };
|
||||||
|
|
||||||
|
public static Operand special(OperandKind kind, SourcePosition position) => new(kind, position);
|
||||||
|
|
||||||
|
public bool isRegister(int index) => kind == OperandKind.Register && registerIndex == index;
|
||||||
|
|
||||||
|
public override string ToString() => kind switch
|
||||||
|
{
|
||||||
|
OperandKind.Register => "V" + registerIndex.ToString("X1"),
|
||||||
|
OperandKind.RegisterRange => "V" + registerIndex.ToString("X1") + "-V" + rangeEnd.ToString("X1"),
|
||||||
|
OperandKind.Immediate => "imm",
|
||||||
|
OperandKind.IndexIndirect => "[I]",
|
||||||
|
_ => kind.ToString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Chip8.Core.Assembly;
|
||||||
|
|
||||||
|
public abstract class Statement
|
||||||
|
{
|
||||||
|
protected Statement(SourcePosition position)
|
||||||
|
{
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourcePosition position { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class LabelStatement : Statement
|
||||||
|
{
|
||||||
|
public LabelStatement(string name, SourcePosition position) : base(position)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string name { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ConstantStatement : Statement
|
||||||
|
{
|
||||||
|
public ConstantStatement(string name, IReadOnlyList<Token> expression, SourcePosition position) : base(position)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string name { get; }
|
||||||
|
public IReadOnlyList<Token> expression { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class OrgStatement : Statement
|
||||||
|
{
|
||||||
|
public OrgStatement(IReadOnlyList<Token> expression, SourcePosition position) : base(position)
|
||||||
|
{
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<Token> expression { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class AlignStatement : Statement
|
||||||
|
{
|
||||||
|
public AlignStatement(IReadOnlyList<Token> expression, SourcePosition position) : base(position)
|
||||||
|
{
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<Token> expression { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class DataStatement : Statement
|
||||||
|
{
|
||||||
|
public DataStatement(bool word, IReadOnlyList<IReadOnlyList<Token>> items, SourcePosition position) : base(position)
|
||||||
|
{
|
||||||
|
this.word = word;
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool word { get; }
|
||||||
|
public IReadOnlyList<IReadOnlyList<Token>> items { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class InstructionStatement : Statement
|
||||||
|
{
|
||||||
|
public InstructionStatement(string mnemonic, IReadOnlyList<Operand> operands, SourcePosition position) : base(position)
|
||||||
|
{
|
||||||
|
this.mnemonic = mnemonic;
|
||||||
|
this.operands = operands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string mnemonic { get; }
|
||||||
|
public IReadOnlyList<Operand> operands { get; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
namespace Chip8.Core.Assembly;
|
||||||
|
|
||||||
|
public enum TokenKind
|
||||||
|
{
|
||||||
|
Identifier,
|
||||||
|
Number,
|
||||||
|
Comma,
|
||||||
|
Colon,
|
||||||
|
Minus,
|
||||||
|
Plus,
|
||||||
|
Star,
|
||||||
|
Slash,
|
||||||
|
Percent,
|
||||||
|
Ampersand,
|
||||||
|
Pipe,
|
||||||
|
Caret,
|
||||||
|
Tilde,
|
||||||
|
ShiftLeft,
|
||||||
|
ShiftRight,
|
||||||
|
LeftParen,
|
||||||
|
RightParen,
|
||||||
|
LeftBracket,
|
||||||
|
RightBracket,
|
||||||
|
EndOfLine,
|
||||||
|
EndOfFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct SourcePosition
|
||||||
|
{
|
||||||
|
public SourcePosition(int line, int column)
|
||||||
|
{
|
||||||
|
this.line = line;
|
||||||
|
this.column = column;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int line { get; }
|
||||||
|
public int column { get; }
|
||||||
|
|
||||||
|
public override string ToString() => "line " + line + ", col " + column;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct Token
|
||||||
|
{
|
||||||
|
public Token(TokenKind kind, string text, int value, SourcePosition position)
|
||||||
|
{
|
||||||
|
this.kind = kind;
|
||||||
|
this.text = text;
|
||||||
|
this.value = value;
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenKind kind { get; }
|
||||||
|
public string text { get; }
|
||||||
|
public int value { get; }
|
||||||
|
public SourcePosition position { get; }
|
||||||
|
|
||||||
|
public bool isIdentifier(string name) =>
|
||||||
|
kind == TokenKind.Identifier && string.Equals(text, name, System.StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public override string ToString() => kind + "('" + text + "')";
|
||||||
|
}
|
||||||
Reference in new issue
Block a user