Skip to content

Commit

Permalink
support declarations in function body
Browse files Browse the repository at this point in the history
  • Loading branch information
caipng committed Apr 21, 2024
1 parent e1dfd4b commit ad60a86
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 16 deletions.
8 changes: 8 additions & 0 deletions src/ast/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ export interface TypedDeclaration extends BaseNode {
declaratorList: TypedInitDeclarator[];
}

export const isTypedDeclaration = (i: TypedBlockItem): i is TypedDeclaration =>
i.type === "Declaration";

export interface TypedefDeclaration extends BaseNode {
type: "TypedefDeclaration";
declaratorList: Typedef[];
Expand Down Expand Up @@ -185,6 +188,7 @@ export interface InitDeclarator extends BaseNode {
export interface TypedInitDeclarator extends BaseNode {
type: "InitDeclarator";
identifier: Identifier;
qualifiedIdentifier?: Identifier;
typeInfo: ObjectTypeInfo;
initializer: TypedInitializer | null;
}
Expand Down Expand Up @@ -338,6 +342,10 @@ export interface TypedCompoundStatement extends BaseNode {
value: TypedBlockItem[];
}

export const isTypedCompoundStatement = (
i: TypedStatement,
): i is TypedCompoundStatement => i.type === "CompoundStatement";

export type BlockItem = Statement | Declaration;

export type TypedBlockItem =
Expand Down
47 changes: 36 additions & 11 deletions src/interpreter/evaluators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
branchInstruction,
callInstruction,
castInstruction,
exitBlockInstruction,
isMarkInstruction,
markInstruction,
popInstruction,
Expand All @@ -88,6 +89,7 @@ import { Endianness } from "../config";
import { RuntimeStack } from "./stack";
import { SHRT_SIZE } from "../constants";
import { checkSimpleAssignmentConstraint, getMember } from "../typing/utils";
import { NO_EFFECTIVE_TYPE } from "./effectiveTypeTable";

export const ASTNodeEvaluator: {
[NodeType in TypedASTNode["type"]]: (
Expand Down Expand Up @@ -134,18 +136,22 @@ export const ASTNodeEvaluator: {
TypedefDeclaration: () => {},
InitDeclarator: (
rt: Runtime,
{ identifier, typeInfo, initializer }: TypedInitDeclarator,
{ identifier, typeInfo, initializer, qualifiedIdentifier }: TypedInitDeclarator,
) => {
if (!rt.symbolTable.inFileScope) {
throw new Error("declarations in functions not implemented");
let address: number;
if (rt.symbolTable.inFileScope) {
address = rt.allocateAndZeroData(typeInfo);
const o = new RuntimeObject(typeInfo, address, identifier, rt.memory);
o.initialized = true;
rt.textAndData.push(o);
} else {
if (!qualifiedIdentifier) throw new Error("missing call to calculateStackFrame");
const frame = rt.stack.peek();
address = rt.stack.rbp + frame[qualifiedIdentifier].address;
}

const address = rt.allocateAndZeroData(typeInfo);
const o = new RuntimeObject(typeInfo, address, identifier, rt.memory);
rt.textAndData.push(o);
rt.symbolTable.addAddress(identifier, address);
rt.effectiveTypeTable.add(address, typeInfo);

if (initializer) evaluateInitializer(initializer, address, typeInfo, rt);
},
InitializerList: () => {
Expand All @@ -155,6 +161,8 @@ export const ASTNodeEvaluator: {
rt: Runtime,
{ value: stmts }: TypedCompoundStatement,
) => {
rt.symbolTable.enterBlock();
rt.agenda.push(exitBlockInstruction());
for (let i = stmts.length - 1; i >= 0; i--) {
rt.agenda.push(stmts[i]);
}
Expand Down Expand Up @@ -712,6 +720,7 @@ export const instructionEvaluator: {
rt.config.endianness,
);
rt.memory.setScalar(address, n, typeInfo, rt.config.endianness);
rt.initTable.add(address, typeInfo);
rt.stash.pushWithoutConversions(
new TemporaryObject(
typeInfo,
Expand All @@ -722,7 +731,9 @@ export const instructionEvaluator: {
}
if (isStructure(typeInfo) && isStructure(o.typeInfo)) {
rt.memory.setObjectBytes(address, o.bytes, typeInfo);
rt.initTable.add(address, typeInfo);
rt.stash.pushWithoutConversions(o);
return;
}
}

Expand All @@ -731,7 +742,7 @@ export const instructionEvaluator: {
[InstructionType.MARK]: (rt: Runtime) => {
const idx = rt.functionCalls.peek();
if (rt.getFunctions()[idx][0] !== "main") {
throw new Error("mark encountered without return");
throw new Error("mark encountered without return (are you missing a return statement?)");
}
// main implicitly returns 0 if no return statement
rt.stash.pushWithoutConversions(
Expand Down Expand Up @@ -794,8 +805,10 @@ export const instructionEvaluator: {
const [fnBody, fnType] = rt.getFunction(Number(fnIdx));
rt.functionCalls.push(Number(fnIdx));
rt.agenda.push(markInstruction());
if (fnBody.value.length === 1) rt.agenda.push(fnBody.value[0]);
else rt.agenda.push(fnBody);
const stmts = fnBody.value
for (let i = stmts.length - 1; i >= 0; i--) {
rt.agenda.push(stmts[i]);
}

const frame = RuntimeStack.calculateStackFrame(
fnType.parameterTypes,
Expand Down Expand Up @@ -833,7 +846,11 @@ export const instructionEvaluator: {
while (!isMarkInstruction(rt.agenda.peek())) rt.agenda.pop();
rt.agenda.pop();
const block = rt.symbolTable.exitBlock();
Object.values(block).forEach((addr) => rt.effectiveTypeTable.remove(addr));
Object.values(block).forEach((addr) => {
const t = rt.effectiveTypeTable.get(addr)
if (t !== NO_EFFECTIVE_TYPE) rt.initTable.remove(addr, t.size)
rt.effectiveTypeTable.remove(addr)
});
rt.stack.pop();
rt.functionCalls.pop();
},
Expand Down Expand Up @@ -960,6 +977,14 @@ export const instructionEvaluator: {
);
}
},
[InstructionType.EXIT_BLOCK]: (rt:Runtime) => {
const block = rt.symbolTable.exitBlock();
Object.values(block).forEach((addr) => {
const t = rt.effectiveTypeTable.get(addr)
if (t !== NO_EFFECTIVE_TYPE) rt.initTable.remove(addr, t.size)
rt.effectiveTypeTable.remove(addr)
});
}
};

const convertValue = (
Expand Down
25 changes: 25 additions & 0 deletions src/interpreter/initializedTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { cloneDeep } from "lodash";
import { ObjectTypeInfo } from "../typing/types";

export class InitializedTable {
private table: Record<number, boolean> = {};

public add(addr: number, t: ObjectTypeInfo): void {
for (let i = addr; i < addr + t.size; i++) this.table[i] = true;
}

public check(addr: number, t: ObjectTypeInfo): boolean {
for (let i = addr; i < addr + t.size; i++) if (!(i in this.table)) return false;
return true;
}

public remove(addr: number, size: number): void {
for (let i = addr; i < addr + size; i++) {
if (i in this.table) delete this.table[i]
}
}

public getTable() {
return cloneDeep(this.table)
}
}
10 changes: 9 additions & 1 deletion src/interpreter/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum InstructionType {
ARITHMETIC_CONVERSION = "ArithmeticConversion",
CAST = "Cast",
ARRAY_SUBSCRIPT = "ArraySubscript",
EXIT_BLOCK ="ExitBlock"
}

export interface BaseInstruction {
Expand Down Expand Up @@ -163,6 +164,12 @@ export const arraySubscriptInstruction = (
evaluateAsLvalue,
});

export interface ExitBlockInstruction extends BaseInstruction {
type: InstructionType.EXIT_BLOCK;
}

export const exitBlockInstruction = () :ExitBlockInstruction => ({type:InstructionType.EXIT_BLOCK});

export type Instruction =
| UnaryOpInstruction
| BinaryOpInstruction
Expand All @@ -176,4 +183,5 @@ export type Instruction =
| AssignInstruction
| ArithmeticConversionInstruction
| CastInstruction
| ArraySubscriptInstruction;
| ArraySubscriptInstruction
| ExitBlockInstruction
14 changes: 12 additions & 2 deletions src/interpreter/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ export class RuntimeObject
implements IdentifiableAndAddressable
{
public readonly address: number;
public readonly identifier: Identifier;
public initialized: boolean;
private readonly memory: Memory;
private _identifier: Identifier;

public constructor(
typeInfo: ObjectTypeInfo,
Expand All @@ -95,11 +96,20 @@ export class RuntimeObject
typeInfo.alignment +
")"
);
this.identifier = identifier;
this._identifier = identifier;
this.memory = memory;
this.initialized = false;
}

public get bytes() {
return this.memory.getObjectBytes(this.address, this.typeInfo);
}

public get identifier() {
return this._identifier;
}

public setIdentifier(i: Identifier) {
this._identifier = i;
}
}
5 changes: 5 additions & 0 deletions src/interpreter/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
EffectiveTypeTable,
EffectiveTypeTableEntry,
} from "./effectiveTypeTable";
import { InitializedTable } from "./initializedTable";

export type TextAndDataEntry = FunctionDesignator | RuntimeObject;

Expand All @@ -43,6 +44,7 @@ export class RuntimeView {
rbpArr: number[];
heap: Record<number, HeapEntry>;
effectiveTypeTable: Record<number, EffectiveTypeTableEntry>;
initTable: InitializedTable;

constructor(rt: Runtime) {
this.agenda = rt.agenda.getArr();
Expand All @@ -59,6 +61,7 @@ export class RuntimeView {
this.rbpArr.push(rt.stack.rbp);
this.heap = rt.heap.getAllocations();
this.effectiveTypeTable = rt.effectiveTypeTable.getTable();
this.initTable = cloneDeep(rt.initTable)
}
}

Expand All @@ -73,6 +76,7 @@ export class Runtime {
public readonly stack: RuntimeStack;
public readonly functionCalls: Stack<number>;
public readonly heap: Heap;
public readonly initTable: InitializedTable;

private functions: [string, TypedCompoundStatement, FunctionType][];
private builtinFunctions: BuiltinFunction[];
Expand All @@ -94,6 +98,7 @@ export class Runtime {
config.memory.heap.baseAddress,
config.memory.heap.baseAddress + config.memory.heap.size,
);
this.initTable = new InitializedTable()

this.functions = [];
this.builtinFunctions = [];
Expand Down
37 changes: 35 additions & 2 deletions src/interpreter/stack.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Identifier, TypedCompoundStatement } from "../ast/types";
import {
Identifier,
TypedCompoundStatement,
isTypedCompoundStatement,
isTypedDeclaration,
isTypedefDeclaration,
} from "../ast/types";
import { ObjectTypeInfo, ParameterTypeAndIdentifier } from "../typing/types";
import { Stack, roundUpM } from "../utils";

Expand Down Expand Up @@ -54,11 +60,11 @@ export class RuntimeStack extends Stack<StackFrame> {

static calculateStackFrame(
params: ParameterTypeAndIdentifier[],
// eslint-disable-next-line @typescript-eslint/no-unused-vars
body: TypedCompoundStatement,
): StackFrame {
const res: StackFrame = {};
let ptr = 0;

for (const p of params) {
if (!p.identifier) throw new Error("param missing identifier");
ptr = roundUpM(ptr, p.type.alignment);
Expand All @@ -68,6 +74,33 @@ export class RuntimeStack extends Stack<StackFrame> {
};
ptr += p.type.size;
}

const identifierPrefix: string[] = [];
const scan = (stmts: TypedCompoundStatement): void => {
let blockNo = 0;
stmts.value.forEach((i) => {
if (isTypedDeclaration(i)) {
i.declaratorList.forEach((j) => {
const typeInfo = j.typeInfo;
const qid =
identifierPrefix.join("::") +
(identifierPrefix.length ? "::" : "") +
j.identifier;
j.qualifiedIdentifier = qid;
ptr = roundUpM(ptr, typeInfo.alignment);
res[qid] = { address: ptr, typeInfo };
ptr += typeInfo.size;
});
} else if (!isTypedefDeclaration(i) && isTypedCompoundStatement(i)) {
identifierPrefix.push("block" + blockNo);
scan(i);
identifierPrefix.pop();
blockNo++;
}
});
};
scan(body);

return res;
}

Expand Down

0 comments on commit ad60a86

Please sign in to comment.