Pointer support (#2)
* Make branches not identical * Removed temporary file * Typecheck - Added `attemptPointerAriehmeticCoercion(Value, Value)` * Typechecker - Moved `attemptPointerAriehmeticCoercion(Value, Value)` to class-level and made privately accessible * Test cases - Added pointer arithmetic in the form of `*(ptr+0)` to `simple_pointer.t` to start testing it out * Typechecker - When handling `BinaryOperatorExpression` call `attemptPointerAriehmeticCoercion(Value, Value)` with both `(vLhsInstr, vRhsInstr)` before we call `vLhsInstr.getInstrType()` and `vRhsInstr.getInstrType()` before `isSameType(vLhsType, vRhsType)`. By doing so we attempt to coerce the types of both instructions if one is a pointer and another is an integer, else do nothing * DGen - When emitting for `PointerDereferenceAssignmentInstruction` we didn't wrap `<expr>` with `()`. So instead of `*(<expre>)` we got `*<expr>` which doesn't work if you're doing pointer arithmetic * Test cases - Added `simple_pointer_cast.t` to test casting (currently broken parsing-wise) DGen - Added a todo for semantic tests for the `simple_pointer_cast.t` test case * Parser - Added a TODO - we need a `parseType()` * Test cases - Removed `simple_cast_complex_type.t` as it is wrong, syntax wise * Test cases - Removed coercion usage, I am only testing the casting here (explicit) * Test cases - Removed `simple_pointer_cast.t` and replace it with `simple_pointer_cast_le.t` which casts the integer pointer to a byte pointer and sets the lowest significant byte (little endian hence at base of integer) to `2+2` DGen - Added semantic test for `simple_pointer_cast_le.t` * Test cases - Update `simple_pointer_cast_le.t` to do some pointer airthmetic at the byte-level of the 32-bit integer DGen - Updated the semantic test code generation for `simple_pointer_cast_le.t` to check for new values * Added 'simple_pointer_cast_le.t' to Emit tests * TypeChecker - Update `isSameType(Type t1, Type t2)` to now handle pointers explicitly and in a recursive manner based on their referred types - This check occurs before the `Integer` type check therefore following the rule of most specific types to least * Test cases - Added new test case `simple_pointer_malloc.t` - Added semantic code test generation for `simple_pointer_malloc.t` - Added `malloc_test.sh` to compile and generate `mem.o` from `mem.c` to link it then with `simple_pointer_malloc.t` - Added `mem.c` external C file to generate the required `mem.o` for linking against `simple_pointer_malloc.t` * Test cases - Updated `malloc_test.sh` to look for any `brk()` system calls and fixed its interpreter path
This commit is contained in:
parent
fca2bac20e
commit
493da1a4e7
|
@ -305,11 +305,18 @@ jobs:
|
|||
run: |
|
||||
./tlang compile source/tlang/testing/simple_pointer.t
|
||||
./tlang.out
|
||||
- name: Simple pointer cast (little endian)
|
||||
run: |
|
||||
././tlang compile source/tlang/testing/simple_pointer_cast_le.t
|
||||
./tlang.out
|
||||
- name: Simple extern
|
||||
run: |
|
||||
chmod +x extern_test.sh
|
||||
./extern_test.sh
|
||||
|
||||
- name: Simple pointer (malloc and free)
|
||||
run: |
|
||||
chmod +x malloc_test.sh
|
||||
./malloc_test.sh
|
||||
##################################
|
||||
####### Deployment section #######
|
||||
##################################
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Compile C to object file as library to link in
|
||||
gcc source/tlang/testing/mem.c -c -o mem.o
|
||||
|
||||
# Compile T to C, then compile C and link with other object file into a final object file
|
||||
./tlang compile source/tlang/testing/simple_pointer_malloc.t -sm HASHMAPPER -et true -pg true -ll mem.o
|
||||
|
||||
# Run the tlang file
|
||||
./tlang.out
|
||||
|
||||
# Run (with strace) to see it
|
||||
strace -e brk ./tlang.out
|
|
@ -445,7 +445,7 @@ public final class DCodeEmitter : CodeEmitter
|
|||
{
|
||||
starsOfLiberty ~= "*";
|
||||
}
|
||||
emit ~= starsOfLiberty~transform(lhsPtrAddrExprInstr);
|
||||
emit ~= starsOfLiberty~"("~transform(lhsPtrAddrExprInstr)~")";
|
||||
|
||||
/* Assignment operator follows */
|
||||
emit ~= " = ";
|
||||
|
@ -815,6 +815,34 @@ int main()
|
|||
assert(t_87bc875d0b65f741b69fb100a0edebc7 == 4);
|
||||
assert(retValue == 6);
|
||||
|
||||
return 0;
|
||||
}`);
|
||||
}
|
||||
else if(cmp(typeChecker.getModule().getName(), "simple_pointer_cast_le") == 0)
|
||||
{
|
||||
file.writeln(`
|
||||
#include<stdio.h>
|
||||
#include<assert.h>
|
||||
int main()
|
||||
{
|
||||
int retValue = thing();
|
||||
assert(t_e159019f766be1a175186a13f16bcfb7 == 256+4);
|
||||
assert(retValue == 256+4+2);
|
||||
|
||||
return 0;
|
||||
}`);
|
||||
}
|
||||
else if(cmp(typeChecker.getModule().getName(), "simple_pointer_malloc") == 0)
|
||||
{
|
||||
file.writeln(`
|
||||
#include<stdio.h>
|
||||
#include<assert.h>
|
||||
int main()
|
||||
{
|
||||
test();
|
||||
|
||||
// TODO: Test the value
|
||||
|
||||
return 0;
|
||||
}`);
|
||||
}
|
||||
|
|
|
@ -316,8 +316,16 @@ public final class TypeChecker
|
|||
{
|
||||
bool same = false;
|
||||
|
||||
/* Handling for pointers */
|
||||
if(typeid(type1) == typeid(type2) && cast(Pointer)type1 !is null)
|
||||
{
|
||||
Pointer p1 = cast(Pointer)type1, p2 = cast(Pointer)type2;
|
||||
|
||||
/* Now check that both of their referred types are the same */
|
||||
return isSameType(p1.getReferredType(), p2.getReferredType());
|
||||
}
|
||||
/* Handling for Integers */
|
||||
if(typeid(type1) == typeid(type2) && cast(Integer)type1 !is null)
|
||||
else if(typeid(type1) == typeid(type2) && cast(Integer)type1 !is null)
|
||||
{
|
||||
Integer i1 = cast(Integer)type1, i2 = cast(Integer)type2;
|
||||
|
||||
|
@ -682,6 +690,52 @@ public final class TypeChecker
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two Value-based instructions this will firstly check if
|
||||
* at least one of the two is of type Pointer, then checks if the
|
||||
* remaining instruction is an of type Integer - the remaining instruction
|
||||
* will then be coerced into a pointer.
|
||||
*
|
||||
* If both are Pointers, neither are pointers or one or the other is
|
||||
* a Pointer and another is non-Integer then nothing will be coerced.
|
||||
* and this function is effectively a no-op.
|
||||
*
|
||||
* Params:
|
||||
* vInstr1 = the first instruction
|
||||
* vInstr2 = the second instruction
|
||||
*/
|
||||
private void attemptPointerAriehmeticCoercion(Value vInstr1, Value vInstr2)
|
||||
{
|
||||
// Get the types of `vInstr1` and `vInstr2` respectively
|
||||
Type t1 = vInstr1.getInstrType();
|
||||
Type t2 = vInstr2.getInstrType();
|
||||
|
||||
// TODO: Check if T1 is a pointer and then if T2 is an integer make it a pointer
|
||||
if(cast(Pointer)t1 && cast(Integer)t2)
|
||||
{
|
||||
Pointer t1Ptr = cast(Pointer)t1;
|
||||
|
||||
Type coercedType = new Pointer(t1Ptr.getReferredType());
|
||||
vInstr2.setInstrType(coercedType);
|
||||
}
|
||||
// TODO: Else check if T2 is a pointer and then if T1 is an integer and make it a pointer
|
||||
else if(cast(Pointer)t2 && cast(Integer)t2)
|
||||
{
|
||||
Pointer t2Ptr = cast(Pointer)t2;
|
||||
|
||||
Type coercedType = new Pointer(t2Ptr.getReferredType());
|
||||
vInstr1.setInstrType(coercedType);
|
||||
}
|
||||
else if(cast(Pointer)t1 && cast(Pointer)t2)
|
||||
{
|
||||
// Do nothing
|
||||
// TODO: Remove this branch
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void typeCheckThing(DNode dnode)
|
||||
|
@ -853,9 +907,18 @@ public final class TypeChecker
|
|||
Value vRhsInstr = cast(Value)popInstr();
|
||||
Value vLhsInstr = cast(Value)popInstr();
|
||||
|
||||
/**
|
||||
* Attempt to coerce the types of both instructions if one is
|
||||
* a pointer and another is an integer, else do nothing
|
||||
*/
|
||||
attemptPointerAriehmeticCoercion(vLhsInstr, vRhsInstr);
|
||||
|
||||
|
||||
Type vRhsType = vRhsInstr.getInstrType();
|
||||
Type vLhsType = vLhsInstr.getInstrType();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* Types must either BE THE SAME or BE COMPATIBLE
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#include<stdlib.h>
|
||||
|
||||
int ctr = 2;
|
||||
|
||||
unsigned long* memAlloc(unsigned long sizeAlloc)
|
||||
{
|
||||
return malloc(sizeAlloc);
|
||||
}
|
||||
|
||||
void memFree(unsigned long* memory)
|
||||
{
|
||||
free(memory);
|
||||
}
|
|
@ -4,7 +4,7 @@ int j;
|
|||
|
||||
int function(int* ptr)
|
||||
{
|
||||
*ptr = 2+2;
|
||||
*(ptr+0) = 2+2;
|
||||
return (*ptr)+1*2;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
module simple_pointer_cast_le;
|
||||
|
||||
int j;
|
||||
|
||||
int ret()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int function(int* ptr)
|
||||
{
|
||||
byte* bytePtr = cast(byte*)ptr;
|
||||
*bytePtr = 2+2;
|
||||
*(bytePtr+1) = 1;
|
||||
|
||||
return (*ptr)+1*2;
|
||||
}
|
||||
|
||||
int thing()
|
||||
{
|
||||
int discardExpr = function(&j);
|
||||
int** l;
|
||||
|
||||
return discardExpr;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
module simple_pointer_malloc;
|
||||
|
||||
extern efunc ubyte* memAlloc(ulong size);
|
||||
extern efunc void memFree(ubyte* ptr);
|
||||
|
||||
void test()
|
||||
{
|
||||
ubyte* memory = memAlloc(10UL);
|
||||
|
||||
for(int i = 0; i < 10; i = i + 1)
|
||||
{
|
||||
*(memory+i) = 65+i;
|
||||
}
|
||||
|
||||
discard memFree(memory);
|
||||
}
|
Loading…
Reference in New Issue