2020-09-10 00:56:16 +00:00
/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
# include <Defs.h>
# include <Data.h>
2021-01-17 06:37:39 +00:00
# include <stdbool.h>
2021-01-20 01:05:41 +00:00
static int ReadParameters ( struct SymbolTableEntry * FunctionSymbol ) {
int TokenType , ParamCount = 0 ;
struct SymbolTableEntry * PrototypePointer = NULL ;
2021-01-18 00:20:58 +00:00
2021-01-20 01:05:41 +00:00
if ( FunctionSymbol ! = NULL )
PrototypePointer = FunctionSymbol - > Start ;
2021-01-17 06:37:39 +00:00
while ( CurrentToken . type ! = LI_RPARE ) {
TokenType = ParseOptionalPointer ( ) ;
VerifyToken ( TY_IDENTIFIER , " identifier " ) ;
2021-01-20 01:05:41 +00:00
if ( PrototypePointer ! = NULL ) {
if ( TokenType ! = PrototypePointer - > Type )
2021-01-18 00:20:58 +00:00
DieDecimal ( " Function paramater of invalid type at index " , ParamCount + 1 ) ;
2021-01-20 01:05:41 +00:00
PrototypePointer = PrototypePointer - > NextSymbol ;
2021-01-18 00:20:58 +00:00
} else {
BeginVariableDeclaration ( TokenType , SC_PARAM ) ;
}
2021-01-17 06:37:39 +00:00
ParamCount + + ;
switch ( CurrentToken . type ) {
case LI_COM :
Tokenise ( & CurrentToken ) ;
break ;
case LI_RPARE :
break ;
default :
DieDecimal ( " Unexpected token in parameter " , CurrentToken . type ) ;
}
}
2020-09-10 00:56:16 +00:00
2021-01-20 01:05:41 +00:00
if ( ( FunctionSymbol ! = NULL ) & & ( ParamCount ! = FunctionSymbol - > Length ) )
DieMessage ( " Invalid number of parameters in prototyped function " , FunctionSymbol - > Name ) ;
2021-01-18 00:20:58 +00:00
2021-01-17 06:37:39 +00:00
return ParamCount ;
}
2020-09-10 00:56:16 +00:00
/*
* Handles the declaration of a type of a variable .
* int newVar ;
*
2021-01-20 01:05:41 +00:00
* It verifies that we have a type keyword followed by a
2020-09-10 00:56:16 +00:00
* unique , non - keyword identifier .
*
2021-01-20 01:05:41 +00:00
* It then stores this variable into the symbol table ,
* and returns the new item .
2020-09-10 00:56:16 +00:00
*
*/
2021-01-20 01:05:41 +00:00
struct SymbolTableEntry * BeginVariableDeclaration ( int Type , int Scope ) {
struct SymbolTableEntry * Symbol = NULL ;
switch ( Scope ) {
case SC_GLOBAL :
if ( FindGlobal ( CurrentIdentifier ) ! = NULL )
DieMessage ( " Invalid redeclaration of global variable " , CurrentIdentifier ) ;
case SC_LOCAL :
case SC_PARAM :
if ( FindLocal ( CurrentIdentifier ) ! = NULL )
DieMessage ( " Invalid redelcaration of local variable " , CurrentIdentifier ) ;
}
2020-09-10 00:56:16 +00:00
2020-11-18 20:49:08 +00:00
if ( CurrentToken . type = = LI_LBRAS ) {
Tokenise ( & CurrentToken ) ;
2021-01-20 01:05:41 +00:00
2020-11-18 20:49:08 +00:00
if ( CurrentToken . type = = LI_INT ) {
2021-01-20 01:05:41 +00:00
switch ( Scope ) {
case SC_GLOBAL :
Symbol = AddSymbol ( CurrentIdentifier , PointerTo ( Type ) , ST_ARR , Scope , 1 , 0 ) ;
break ;
case SC_LOCAL :
case SC_PARAM :
Die ( " Local arrays are unimplemented " ) ;
}
2020-09-13 22:41:46 +00:00
}
2020-09-10 00:56:16 +00:00
2020-11-18 20:49:08 +00:00
Tokenise ( & CurrentToken ) ;
VerifyToken ( LI_RBRAS , " ] " ) ;
} else {
2021-01-20 01:05:41 +00:00
Symbol = AddSymbol ( CurrentIdentifier , Type , ST_VAR , Scope , 1 , 0 ) ;
2020-09-13 22:41:46 +00:00
}
2020-11-18 20:49:08 +00:00
2021-01-20 01:05:41 +00:00
return Symbol ;
2020-09-10 00:56:16 +00:00
}
2020-09-13 22:41:46 +00:00
struct ASTNode * ParseFunction ( int Type ) {
2020-09-10 00:56:16 +00:00
struct ASTNode * Tree ;
struct ASTNode * FinalStatement ;
2021-01-20 01:05:41 +00:00
struct SymbolTableEntry * OldFunction , * NewFunction = NULL ;
2021-01-18 00:20:58 +00:00
int SymbolSlot , BreakLabel , ParamCount , ID ;
2021-01-20 01:05:41 +00:00
if ( ( OldFunction = FindSymbol ( CurrentIdentifier ) ) ! = NULL )
if ( OldFunction - > Storage ! = ST_FUNC )
OldFunction = NULL ;
if ( OldFunction = = NULL ) {
2021-01-18 00:20:58 +00:00
BreakLabel = NewLabel ( ) ;
2021-01-20 01:05:41 +00:00
NewFunction = AddSymbol ( CurrentIdentifier , Type , ST_FUNC , SC_GLOBAL , BreakLabel , 0 ) ;
2021-01-18 00:20:58 +00:00
}
2020-09-10 00:56:16 +00:00
2021-01-18 00:20:58 +00:00
VerifyToken ( LI_LPARE , " ( " ) ;
2021-01-20 01:05:41 +00:00
ParamCount = ReadParameters ( OldFunction ) ;
2021-01-18 00:20:58 +00:00
VerifyToken ( LI_RPARE , " ) " ) ;
2020-09-10 00:56:16 +00:00
2021-01-20 01:05:41 +00:00
if ( NewFunction ) {
NewFunction - > Elements = ParamCount ;
NewFunction - > Start = Params ;
OldFunction = NewFunction ;
2021-01-18 00:20:58 +00:00
}
2020-09-10 00:56:16 +00:00
2021-01-20 01:05:41 +00:00
Params = ParamsEnd = NULL ;
2021-01-18 00:20:58 +00:00
if ( CurrentToken . type = = LI_SEMIC ) {
Tokenise ( & CurrentToken ) ;
return NULL ;
}
2021-01-20 01:05:41 +00:00
printf ( " \n Identified%sfunction %s of return type %s, end label %d \n " , ( OldFunction = = NULL ) ? " new " : " overloaded " , OldFunction - > Name , TypeNames ( Type ) , BreakLabel ) ;
2020-11-25 22:53:50 +00:00
2021-01-20 01:05:41 +00:00
FunctionEntry = OldFunction ;
2020-09-10 00:56:16 +00:00
Tree = ParseCompound ( ) ;
if ( Type ! = RET_VOID ) {
// Functions with one statement have no composite node, so we have to check
FinalStatement = ( Tree - > Operation = = OP_COMP ) ? Tree - > Right : Tree ;
if ( FinalStatement = = NULL | | FinalStatement - > Operation ! = OP_RET ) {
Die ( " Function with non-void type does not return " ) ;
}
}
2021-01-20 01:05:41 +00:00
return ConstructASTBranch ( OP_FUNC , Tree - > ExprType , Tree , OldFunction , BreakLabel ) ;
2020-09-10 00:56:16 +00:00
}
/*
* Handles the logic for return .
* //TODO: No brackets
* //TODO: Type inference
*
*
*/
struct ASTNode * ReturnStatement ( ) {
struct ASTNode * Tree ;
2021-01-20 01:05:41 +00:00
int ReturnType ;
2020-09-10 00:56:16 +00:00
2021-01-20 01:05:41 +00:00
if ( FunctionEntry - > Type = = RET_VOID )
2020-09-10 00:56:16 +00:00
Die ( " Attempt to return from void function " ) ;
VerifyToken ( KW_RETURN , " return " ) ;
VerifyToken ( LI_LPARE , " ( " ) ; // TODO: Make optional! Reject?
Tree = ParsePrecedenceASTNode ( 0 ) ;
2020-11-15 06:40:05 +00:00
/*
2020-09-10 00:56:16 +00:00
ReturnType = Tree - > ExprType ;
FunctionType = Symbols [ CurrentFunction ] . Type ;
2020-11-15 06:40:05 +00:00
*/
2020-09-10 00:56:16 +00:00
2021-01-20 01:05:41 +00:00
Tree = MutateType ( Tree , FunctionEntry - > Type , 0 ) ;
2020-11-15 06:40:05 +00:00
if ( Tree = = NULL )
2020-09-10 00:56:16 +00:00
Die ( " Returning a value of incorrect type for function " ) ;
2020-11-15 06:40:05 +00:00
/*
2020-09-10 00:56:16 +00:00
if ( ReturnType )
Tree = ConstructASTBranch ( ReturnType , FunctionType , Tree , 0 ) ;
2020-11-15 06:40:05 +00:00
*/
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( OP_RET , RET_NONE , Tree , FunctionEntry , 0 ) ;
2020-09-10 00:56:16 +00:00
2021-01-20 01:05:41 +00:00
printf ( " \t \t Returning from function %s \n " , FunctionEntry - > Name ) ;
2020-09-10 00:56:16 +00:00
VerifyToken ( LI_RPARE , " ) " ) ; // TODO: OPTIONALISE!
return Tree ;
}
/*
2020-09-14 01:05:24 +00:00
* Handles Identifiers .
2020-09-10 00:56:16 +00:00
*
2020-09-14 01:05:24 +00:00
* This is called for any of :
* - Calling a function
* - Assigning an lvalue variable
* - Performing arithmetic on a variable
* - Performing arithmetic with the return values of function calls
2020-09-10 00:56:16 +00:00
*
2020-09-14 01:05:24 +00:00
* For the case where you ' re assigning an l - value ;
* You can assign with another assignment ,
* a statement , a function or a literal .
2020-09-10 00:56:16 +00:00
*
*/
2020-11-15 06:40:05 +00:00
/*
2020-09-10 00:56:16 +00:00
struct ASTNode * ParseIdentifier ( ) {
struct ASTNode * Left , * Right , * Tree ;
int LeftType , RightType ;
int ID ;
VerifyToken ( TY_IDENTIFIER , " ident " ) ;
2020-09-13 01:26:49 +00:00
printf ( " \t \t After parsing, the identifier name is %s, id %d in the symbol table. \n " , CurrentIdentifier , FindSymbol ( CurrentIdentifier ) ) ;
2020-09-12 01:52:51 +00:00
2020-09-10 00:56:16 +00:00
if ( CurrentToken . type = = LI_LPARE )
return CallFunction ( ) ;
if ( ( ID = FindSymbol ( CurrentIdentifier ) ) = = - 1 ) {
printf ( " Symbol %s not in table. Table contents: %s, %s \n " , CurrentIdentifier , Symbols [ 0 ] . Name , Symbols [ 1 ] . Name ) ;
DieMessage ( " Undeclared Variable " , CurrentIdentifier ) ;
}
Right = ConstructASTLeaf ( LV_IDENT , Symbols [ ID ] . Type , ID ) ;
VerifyToken ( LI_EQUAL , " = " ) ;
Left = ParsePrecedenceASTNode ( 0 ) ;
LeftType = Left - > ExprType ;
RightType = Right - > ExprType ;
2020-09-14 01:05:24 +00:00
Left = MutateType ( Left , RightType , 0 ) ;
if ( ! Left )
Die ( " Incompatible types in assignment " ) ;
2020-09-10 00:56:16 +00:00
if ( LeftType )
Left = ConstructASTBranch ( LeftType , Right - > ExprType , Left , 0 ) ;
Tree = ConstructASTNode ( OP_ASSIGN , RET_INT , Left , NULL , Right , 0 ) ;
return Tree ;
2020-11-15 06:40:05 +00:00
} */
2020-09-10 00:56:16 +00:00
struct ASTNode * IfStatement ( ) {
struct ASTNode * Condition , * True , * False = NULL ;
VerifyToken ( KW_IF , " if " ) ;
VerifyToken ( LI_LPARE , " ( " ) ;
Condition = ParsePrecedenceASTNode ( 0 ) ;
// Limit if(x) to =? != < > <= =>
// No null checking, no arithmetic, no functions.
// TODO: this
if ( Condition - > Operation < OP_EQUAL | | Condition - > Operation > OP_GREATE )
2021-01-20 01:05:41 +00:00
Condition = ConstructASTBranch ( OP_BOOLCONV , Condition - > ExprType , Condition , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
VerifyToken ( LI_RPARE , " ) " ) ;
True = ParseCompound ( ) ;
if ( CurrentToken . type = = KW_ELSE ) {
Tokenise ( & CurrentToken ) ;
False = ParseCompound ( ) ;
}
2021-01-20 01:05:41 +00:00
return ConstructASTNode ( OP_IF , RET_NONE , Condition , True , False , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
}
struct ASTNode * WhileStatement ( ) {
struct ASTNode * Condition , * Body ;
VerifyToken ( KW_WHILE , " while " ) ;
VerifyToken ( LI_LPARE , " ( " ) ;
Condition = ParsePrecedenceASTNode ( 0 ) ;
2020-11-24 00:21:08 +00:00
2020-09-10 00:56:16 +00:00
if ( Condition - > Operation < OP_EQUAL | | Condition - > Operation > OP_GREATE )
2021-01-20 01:05:41 +00:00
Condition = ConstructASTBranch ( OP_BOOLCONV , Condition - > ExprType , Condition , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
VerifyToken ( LI_RPARE , " ) " ) ;
Body = ParseCompound ( ) ;
2021-01-20 01:05:41 +00:00
return ConstructASTNode ( OP_LOOP , RET_NONE , Condition , NULL , Body , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
}
struct ASTNode * ForStatement ( ) {
// for (preop; condition; postop) {
// body
//}
struct ASTNode * Condition , * Body ;
struct ASTNode * Preop , * Postop ;
struct ASTNode * Tree ;
VerifyToken ( KW_FOR , " for " ) ;
VerifyToken ( LI_LPARE , " ( " ) ;
Preop = ParseStatement ( ) ;
VerifyToken ( LI_SEMIC , " ; " ) ;
Condition = ParsePrecedenceASTNode ( 0 ) ;
if ( Condition - > Operation < OP_EQUAL | | Condition - > Operation > OP_GREATE )
2021-01-20 01:05:41 +00:00
Condition = ConstructASTBranch ( OP_BOOLCONV , Condition - > ExprType , Condition , NULL , 0 ) ;
2020-11-24 13:17:01 +00:00
2020-09-10 00:56:16 +00:00
VerifyToken ( LI_SEMIC , " ; " ) ;
Postop = ParseStatement ( ) ;
VerifyToken ( LI_RPARE , " ) " ) ;
Body = ParseCompound ( ) ;
// We need to be able to skip over the body and the postop, so we group them together.
2021-01-20 01:05:41 +00:00
Tree = ConstructASTNode ( OP_COMP , RET_NONE , Body , NULL , Postop , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
// We need to be able to jump to the top of the condition and fall through to the body,
// so we group it with the last block
2021-01-20 01:05:41 +00:00
Tree = ConstructASTNode ( OP_LOOP , RET_NONE , Condition , NULL , Tree , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
// We need to append the postop to the loop, to form the final for loop
2021-01-20 01:05:41 +00:00
return ConstructASTNode ( OP_COMP , RET_NONE , Preop , NULL , Tree , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
}
struct ASTNode * PrintStatement ( void ) {
struct ASTNode * Tree ;
int LeftType , RightType ;
VerifyToken ( KW_PRINT , " print " ) ;
Tree = ParsePrecedenceASTNode ( 0 ) ;
LeftType = RET_INT ;
RightType = Tree - > ExprType ;
2020-09-14 01:05:24 +00:00
Tree = MutateType ( Tree , RightType , 0 ) ;
if ( ! Tree )
2020-09-10 00:56:16 +00:00
DieDecimal ( " Attempting to print an invalid type: " , RightType ) ;
if ( RightType )
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( RightType , RET_INT , Tree , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( OP_PRINT , RET_NONE , Tree , NULL , 0 ) ;
2020-09-10 00:56:16 +00:00
//ParseAST(Tree);
return Tree ;
2020-09-13 01:26:49 +00:00
}
2020-11-23 21:42:32 +00:00
struct ASTNode * PostfixStatement ( ) {
struct ASTNode * Tree ;
2021-01-20 01:05:41 +00:00
struct SymbolTableEntry * Entry ;
2020-11-23 21:42:32 +00:00
Tokenise ( & CurrentToken ) ;
// If we get here, we're one of three things:
// - Function
// - Array
// - Variable
if ( CurrentToken . type = = LI_LPARE )
return CallFunction ( ) ;
if ( CurrentToken . type = = LI_LBRAS )
return AccessArray ( ) ;
// If we get here, we must be a variable.
// There's no guarantees that the variable is in
// the symbol table, though.
2021-01-20 01:05:41 +00:00
if ( ( Entry = FindSymbol ( CurrentIdentifier ) ) = = NULL | | Entry - > Structure ! = ST_VAR )
2020-11-23 21:42:32 +00:00
DieMessage ( " Unknown Variable " , CurrentIdentifier ) ;
// Here we check for postincrement and postdecrement.
switch ( CurrentToken . type ) {
case PPMM_PLUS :
Tokenise ( & CurrentToken ) ;
2021-01-20 01:05:41 +00:00
Tree = ConstructASTLeaf ( OP_POSTINC , Entry - > Type , Entry , 0 ) ;
2020-11-23 21:42:32 +00:00
break ;
case PPMM_MINUS :
Tokenise ( & CurrentToken ) ;
2021-01-20 01:05:41 +00:00
Tree = ConstructASTLeaf ( OP_POSTDEC , Entry - > Type , Entry , 0 ) ;
2020-11-23 21:42:32 +00:00
break ;
default :
2021-01-20 01:05:41 +00:00
Tree = ConstructASTLeaf ( REF_IDENT , Entry - > Type , Entry , 0 ) ;
2020-11-23 21:42:32 +00:00
}
return Tree ;
}
2020-09-13 01:26:49 +00:00
struct ASTNode * PrefixStatement ( ) {
struct ASTNode * Tree ;
switch ( CurrentToken . type ) {
2020-11-23 21:42:32 +00:00
case BOOL_INVERT :
Tokenise ( & CurrentToken ) ;
Tree = PrefixStatement ( ) ;
Tree - > RVal = 1 ;
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( OP_BOOLNOT , Tree - > ExprType , Tree , NULL , 0 ) ;
2020-11-23 21:42:32 +00:00
break ;
case BIT_NOT :
Tokenise ( & CurrentToken ) ;
Tree = PrefixStatement ( ) ;
Tree - > RVal = 1 ;
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( OP_BITNOT , Tree - > ExprType , Tree , NULL , 0 ) ;
2020-11-23 21:42:32 +00:00
break ;
2020-11-24 13:17:01 +00:00
case AR_MINUS :
Tokenise ( & CurrentToken ) ;
Tree = PrefixStatement ( ) ;
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( OP_NEGATE , Tree - > ExprType , Tree , NULL , 0 ) ;
2020-11-24 13:17:01 +00:00
break ;
2020-11-23 21:42:32 +00:00
case PPMM_PLUS :
Tokenise ( & CurrentToken ) ;
Tree = PrefixStatement ( ) ;
if ( Tree - > Operation ! = REF_IDENT )
Die ( " ++ not followed by identifier " ) ;
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( OP_PREINC , Tree - > ExprType , Tree , NULL , 0 ) ;
2020-11-23 21:42:32 +00:00
break ;
case PPMM_MINUS :
Tokenise ( & CurrentToken ) ;
Tree = PrefixStatement ( ) ;
if ( Tree - > Operation ! = REF_IDENT )
Die ( " -- not followed by identifier " ) ;
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( OP_PREDEC , Tree - > ExprType , Tree , NULL , 0 ) ;
2020-11-23 21:42:32 +00:00
break ;
case BIT_AND :
2020-09-13 01:26:49 +00:00
Tokenise ( & CurrentToken ) ;
// To allow things like:
// x = &&y;
// We need to recursively parse prefixes;
Tree = PrefixStatement ( ) ;
if ( Tree - > Operation ! = REF_IDENT )
Die ( " & must be followed by another & or an identifier. " ) ;
Tree - > Operation = OP_ADDRESS ;
Tree - > ExprType = PointerTo ( Tree - > ExprType ) ;
break ;
case AR_STAR :
Tokenise ( & CurrentToken ) ;
Tree = PrefixStatement ( ) ;
if ( Tree - > Operation ! = REF_IDENT & & Tree - > Operation ! = OP_DEREF )
Die ( " * must be followed by another * or an identifier. " ) ;
2020-11-15 06:40:05 +00:00
2021-01-20 01:05:41 +00:00
Tree = ConstructASTBranch ( OP_DEREF , ValueAt ( Tree - > ExprType ) , Tree , NULL , 0 ) ;
2020-09-13 01:26:49 +00:00
break ;
default :
Tree = ParsePrimary ( ) ;
2020-11-15 06:40:05 +00:00
2020-09-13 01:26:49 +00:00
}
return Tree ;
2020-09-10 00:56:16 +00:00
}