IFPSTools.NET/LibIFPSCC/ABT/Expressions.cs
zc e16c00799d ifpscc: initial commit
libifpscc: initial commit
readme: document ifpscc/libifpscc
license: add credits for ifpscc/libifpscc (derived from code also MIT licensed)
libifps: make additional fields/types public for libifpscc
libifps: fix field documentation for some opcodes
libifps: fix loading functions that are not exported
libifps: allow saving a nonexistant primitive type if the same primitive type was added already
libifps: fix parsing Extended constants
libifps: fix ushort/short being mapped to the wrong types in one table
csproj: set Prefer32Bit=false for release builds
2023-03-28 17:24:19 +01:00

237 lines
6.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using CodeGeneration;
namespace ABT {
// Expr
// ========================================================================
/// <summary>
/// The cdecl calling convention:
/// 1. arguments are passed on the stack, right to left.
/// 2. int values and pointer values are returned in %eax.
/// 3. floats are returned in %st(0).
/// 4. when calling a function, %st(0) ~ %st(7) are all free.
/// 5. functions are free to use %eax, %ecx, %edx, because caller needs to save them.
/// 6. stack must be aligned to 4 bytes (before gcc 4.5, for gcc 4.5+, aligned to 16 bytes).
/// </summary>
public abstract partial class Expr : IStoredLineInfo {
protected Expr() { }
/// <summary>
/// Whether the Value is known at compile time.
/// </summary>
public virtual Boolean IsConstExpr => false;
/// <summary>
/// Whether the expression refers to an object (that can be assigned to).
/// </summary>
public abstract Boolean IsLValue { get; }
public abstract Env Env { get; }
public abstract ExprType Type { get; }
public int Line { get; private set; }
public int Column { get; private set; }
public void Copy(ILineInfo info)
{
Line = info.Line;
Column = info.Column;
}
}
public sealed partial class ExprInitList : Expr
{
public ExprInitList(InitList list, Env env) {
this.List = list;
this.Env = env;
}
public InitList List { get; }
public override Env Env { get; }
private ExprType m_Type = null;
public void CoerceType(ExprType type)
{
if (m_Type == null) m_Type = type;
}
public override ExprType Type => m_Type;
public override Boolean IsLValue => !(Type is FunctionType);
}
public sealed partial class Variable : Expr {
public Variable(ExprType type, String name, Env env) {
this.Name = name;
this.Env = env;
this.Type = type;
}
public String Name { get; }
public override Env Env { get; }
public override ExprType Type { get; }
public override Boolean IsLValue => !(Type is FunctionType);
}
public sealed partial class AssignList : Expr {
public AssignList(ImmutableList<Expr> exprs, ILineInfo info) {
if (exprs.Count == 0) {
throw new InvalidOperationException("Need at least one expression.").Attach(info);
}
this.Exprs = exprs;
}
public ImmutableList<Expr> Exprs { get; }
public override Env Env => this.Exprs.Last().Env;
public override Boolean IsLValue => false;
public override ExprType Type => this.Exprs.Last().Type;
}
public sealed partial class Assign : Expr {
public Assign(Expr left, Expr right) {
this.Left = left;
this.Right = right;
if (!this.Left.IsLValue) {
throw new InvalidOperationException("Can only assign to lvalue.").Attach(left);
}
}
public Expr Left { get; }
public Expr Right { get; }
public override Env Env => this.Right.Env;
public override Boolean IsLValue => false;
public override ExprType Type => this.Left.Type.GetQualifiedType(false, false);
}
public sealed partial class ConditionalExpr : Expr {
public ConditionalExpr(Expr cond, Expr trueExpr, Expr falseExpr, ExprType type) {
this.Cond = cond;
this.TrueExpr = trueExpr;
this.FalseExpr = falseExpr;
this.Type = type;
}
public readonly Expr Cond;
public readonly Expr TrueExpr;
public readonly Expr FalseExpr;
public override Boolean IsLValue => false;
public override ExprType Type { get; }
public override Env Env => this.FalseExpr.Env;
}
public sealed partial class FuncCall : Expr {
public FuncCall(Expr func, FunctionType funcType, List<Expr> args) {
this.Func = func;
this.FuncType = funcType;
this.Args = args;
}
public Expr Func { get; }
public FunctionType FuncType { get; }
public IReadOnlyList<Expr> Args { get; }
public override ExprType Type => this.FuncType.ReturnType;
public override Env Env => this.Args.Any() ? this.Args.Last().Env : this.Func.Env;
public override Boolean IsLValue => false;
}
/// <summary>
/// Expr.name: Expr must be a struct or union.
/// </summary>
public sealed partial class Attribute : Expr {
public Attribute(Expr expr, String name, ExprType type) {
this.Expr = expr;
this.Name = name;
this.Type = type;
}
public Expr Expr { get; }
public String Name { get; }
public override Env Env => this.Expr.Env;
public override ExprType Type { get; }
// You might want to think of some special case like this.
// struct EvilStruct {
// int a[10];
// } evil;
// evil.a <--- is this an lvalue?
// Yes, it is. It cannot be assigned, but that's because of the wrong Type.
public override Boolean IsLValue => this.Expr.IsLValue;
}
/// <summary>
/// &amp;Expr: get the address of Expr.
/// </summary>
public sealed partial class Reference : Expr {
public Reference(Expr expr) {
this.Expr = expr;
this.Type = new PointerType(expr.Type);
}
public Expr Expr { get; }
public override Env Env => this.Expr.Env;
public override ExprType Type { get; }
// You might want to think of some special case like this.
// int *a;
// &(*a) = 3; // Is this okay?
// But this should lead to an error: lvalue required.
// The 'reference' operator only gets the 'current address'.
public override Boolean IsLValue => false;
}
/// <summary>
/// *Expr: Expr must be a pointer.
///
/// Arrays and functions are implicitly converted to pointers.
///
/// This is an lvalue, so it has an address.
/// </summary>
public sealed partial class Dereference : Expr {
public Dereference(Expr expr, ExprType type) {
this.Expr = expr;
this.Type = type;
}
public Expr Expr { get; }
public override Env Env => this.Expr.Env;
public override Boolean IsLValue => true;
public override ExprType Type { get; }
}
}