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