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 19:22:15 +00:00
/*
* Handles reading in a comma - separated list of declarations .
* Erythro treats structs , enums and function parameters the same in this regard -
* comma separated .
*
* C and C + + tend to treat enums and structs differently - the former separated by commas ,
* the latter separated by semicolons .
*
* Note that since functions are read in through parentheses , and structs / enums are read in
* through brackets , the end character is configurable .
*
* @ param FunctionSymbol : The Symbol Table Entry of the current function , if applicable .
* @ param Storage : The Storage Scope of this declaration list .
* @ param End : The end token , in terms of TokenTypes enum values .
* @ return the amount of declarations read in .
*
*/
static int ReadDeclarationList ( struct SymbolTableEntry * FunctionSymbol , int Storage , int End ) {
2021-01-20 01:05:41 +00:00
int TokenType , ParamCount = 0 ;
2021-01-20 19:22:15 +00:00
struct SymbolTableEntry * PrototypePointer = NULL , * Composite ;
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 ) {
2021-01-22 01:01:53 +00:00
TokenType = ParseOptionalPointer ( FunctionSymbol ) ;
2021-01-17 06:37:39 +00:00
VerifyToken ( TY_IDENTIFIER , " identifier " ) ;
2021-01-22 01:01:53 +00:00
printf ( " \t Reading a new element: %s of type %d \n " , CurrentIdentifier , TokenType ) ;
2021-01-20 01:05:41 +00:00
if ( PrototypePointer ! = NULL ) {
if ( TokenType ! = PrototypePointer - > Type )
2021-01-22 01:01:53 +00:00
DieDecimal ( " Function parameter 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 {
2021-01-20 19:22:15 +00:00
BeginVariableDeclaration ( TokenType , Composite , Storage ) ;
2021-01-18 00:20:58 +00:00
}
2021-01-17 06:37:39 +00:00
ParamCount + + ;
2021-01-20 19:22:15 +00:00
if ( ( CurrentToken . type ! = LI_COM ) & & ( CurrentToken . type ! = End ) )
DieDecimal ( " Unexpected token in parameter " , CurrentToken . type ) ;
if ( CurrentToken . type = = LI_COM )
Tokenise ( ) ;
2021-01-17 06:37:39 +00:00
}
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
2021-01-20 19:22:15 +00:00
/*
* Handles the declaration of a new struct .
* struct thisStct { int x , int y , int z } ;
*
* Verifies that the current identifier is not used ,
* verifies that this is not a redefinition ( excluding
* the case where there is a declaration but no definition )
* and then saves it into the Structs symbol table .
*
* @ return the Symbol Table entry of this new struct .
*/
struct SymbolTableEntry * BeginStructDeclaration ( ) {
struct SymbolTableEntry * Composite = NULL , * Member ;
int Offset ;
Tokenise ( ) ;
if ( CurrentToken . type = = TY_IDENTIFIER ) {
Composite = FindStruct ( CurrentIdentifier ) ;
Tokenise ( ) ;
}
if ( CurrentToken . type ! = LI_LBRAC ) {
if ( Composite = = NULL )
DieMessage ( " Unknown Struct " , CurrentIdentifier ) ;
return Composite ;
}
if ( Composite )
DieMessage ( " Redefinition of struct " , CurrentIdentifier ) ;
Composite = AddSymbol ( CurrentIdentifier , DAT_STRUCT , 0 , SC_STRUCT , 0 , 0 , NULL ) ;
Tokenise ( ) ;
2021-01-22 01:01:53 +00:00
printf ( " Reading a struct declaration.. \n " ) ;
ReadDeclarationList ( NULL , SC_MEMBER , LI_RBRAC ) ;
VerifyToken ( LI_RBRAC , " } " ) ;
2021-01-20 19:22:15 +00:00
Composite - > Start = StructMembers ;
StructMembers = StructMembersEnd = NULL ;
Member = Composite - > Start ;
Member - > SinkOffset = 0 ;
Offset = TypeSize ( Member - > Type , Member - > CompositeType ) ;
for ( Member = Member - > NextSymbol ; Member ! = NULL ; Member = Member - > NextSymbol ) {
Member - > SinkOffset = AsAlignMemory ( Member - > Type , Offset , 1 ) ;
Offset + = TypeSize ( Member - > Type , Member - > CompositeType ) ;
}
Composite - > Length = Offset ;
return Composite ;
}
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 19:22:15 +00:00
* It then stores this variable into the appropriate symbol table ,
2021-01-20 01:05:41 +00:00
* and returns the new item .
2020-09-10 00:56:16 +00:00
*
2021-01-20 19:22:15 +00:00
* @ return the Symbol Table entry of this new variable .
2020-09-10 00:56:16 +00:00
*/
2021-01-20 19:22:15 +00:00
struct SymbolTableEntry * BeginVariableDeclaration ( int Type , struct SymbolTableEntry * Composite , int Scope ) {
2021-01-20 01:05:41 +00:00
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 )
2021-01-20 19:22:15 +00:00
DieMessage ( " Invalid redeclaration of local variable " , CurrentIdentifier ) ;
case SC_MEMBER :
if ( FindMember ( CurrentIdentifier ) ! = NULL )
DieMessage ( " Invalid redeclaration of Enum/Struct member " , CurrentIdentifier ) ;
2021-01-20 01:05:41 +00:00
}
2020-09-10 00:56:16 +00:00
2020-11-18 20:49:08 +00:00
if ( CurrentToken . type = = LI_LBRAS ) {
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
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 :
2021-01-20 19:22:15 +00:00
Symbol = AddSymbol ( CurrentIdentifier , PointerTo ( Type ) , ST_ARR , Scope , 1 , 0 , NULL ) ;
2021-01-20 01:05:41 +00:00
break ;
case SC_LOCAL :
case SC_PARAM :
2021-01-20 19:22:15 +00:00
case SC_MEMBER :
2021-01-20 01:05:41 +00:00
Die ( " Local arrays are unimplemented " ) ;
}
2020-09-13 22:41:46 +00:00
}
2020-09-10 00:56:16 +00:00
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-11-18 20:49:08 +00:00
VerifyToken ( LI_RBRAS , " ] " ) ;
} else {
2021-01-20 19:22:15 +00:00
Symbol = AddSymbol ( CurrentIdentifier , Type , ST_VAR , Scope , 1 , 0 , Composite ) ;
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
}
2021-01-20 19:22:15 +00:00
/*
* Handles the declaration of a new function .
* Verifies that the identifier is not taken ( excluding the case
* where there is a declaration but no definition )
* Parses the list of parameters if present
* Saves the function prototype if there is no body
* Generates and saves the break - out point label
*
* @ param Type : The return type of the function
* @ return the AST for this function
*
*/
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 19:22:15 +00:00
NewFunction = AddSymbol ( CurrentIdentifier , Type , ST_FUNC , SC_GLOBAL , BreakLabel , 0 , NULL ) ;
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-22 01:01:53 +00:00
ParamCount = ReadDeclarationList ( OldFunction , SC_GLOBAL , LI_RPARE ) ;
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 ) {
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2021-01-18 00:20:58 +00:00
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 ) ;
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
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 ;
}
2021-01-20 19:22:15 +00:00
2020-09-10 00:56:16 +00:00
/*
2021-01-20 19:22:15 +00:00
* Handles the surrounding logic for If statements .
*
* If statements have the basic form :
* * if ( condition ) body
* * if ( condition )
* body
* * if ( condition ) {
* body
* }
2020-09-10 00:56:16 +00:00
*
2021-01-20 19:22:15 +00:00
* Conditions may be any truthy statement ( such as a pointer ,
* object , integer ) , as conditions not recognized are auto -
* matically converted to booleans .
2020-09-10 00:56:16 +00:00
*
2021-01-20 19:22:15 +00:00
* This meaning , any object that can be resolved to 0 or NULL
* can be placed as the condition and used as a check .
*
* For example :
* struct ASTNode * Node = NULL ;
* if ( Node ) {
* // This will not run, as Node is ((void*)0)
* }
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 ) {
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-09-10 00:56:16 +00:00
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
}
2021-01-20 19:22:15 +00:00
/*
* Handles the surrounding logic for While loops .
*
* While loops have the basic form :
* while ( condition ) { body }
*
* When reaching the condition ( which alike an If statement ,
* can be any truthy value ) , if it resolves to true :
* The body is executed , and immediately the condition is checked
* again .
* This repeats until the condition resolves false , at which point
* the loop executes no more .
*
* This can be prototyped as the following pseudo - assembler :
*
* cond :
* check < condition >
* jne exit
* < body >
* jump cond
* exit :
* < more code >
*
* @ return the AST of this statement
*
*/
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
}
2021-01-20 19:22:15 +00:00
/*
* Handles the surrounding logic for For loops .
*
* They have the basic form of :
* for ( init ; condition ; iterator ) { body }
*
* The initialiser is run only once upon reaching the for loop .
* Then the condition is checked , and if true , the body is executed .
* After execution of the body , the iterator is run and the condition
* checked again .
*
* It can be prototyped as the following pseudo - assembler code :
*
* for :
* < init >
* cond :
* check < condition >
* jne exit
* < body >
* < iterator >
* jump cond
* exit :
* < loop exit >
*
* In the case of the implementation , " init " is the preoperator ,
* " iterator " is the postoperator .
*
* @ return the AST of this statement
*/
2020-09-10 00:56:16 +00:00
struct ASTNode * ForStatement ( ) {
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
}
2021-01-20 19:22:15 +00:00
/*
* Handles the surrounding logic for the Print statement .
*
* This is a legacy hold - over from the early testing , and it
* serves merely as a wrapper around the cstdlib printf function .
*
* It does , however ( //TODO), attempt to guess the type that you
* want to print , which takes a lot of the guesswork out of printing .
*
* @ return the AST of this statement
*/
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 19:22:15 +00:00
Tree = ConstructASTBranch ( Tree - > Right - > Operation , 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
}
2021-01-20 19:22:15 +00:00
/*
* Handles the surrounding logic for all of the logical and semantic
* postfixes .
*
* Postfixes are tokens that are affixed to the end of another , and
* change behaviour in some way . These can be added calculations ,
* some form of transformation , or other .
*
* A current list of postfixes :
* * ( ) : Call a function
* * [ ] : Index or define an array .
* * + + : Increment a variable AFTER it is returned
* NOTE : there is a prefix variant of this for incrementing BEFOREhand .
* * - - : Decrement a variable AFTER it is returned
* NOTE : there is a prefix variant of this for decrementing BEFOREhand .
*
* Planned postfixes :
* * > > : Arithmetic - Shift - Right a variable by one ( Divide by two )
* NOTE : there is a prefix variant of this for shifting left - multiplying by two .
*
* @ return the AST of the statement plus its ' postfix
*/
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
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-11-23 21:42:32 +00:00
if ( CurrentToken . type = = LI_LPARE )
return CallFunction ( ) ;
if ( CurrentToken . type = = LI_LBRAS )
return AccessArray ( ) ;
// If we get here, we must be a variable.
2021-01-20 19:22:15 +00:00
// (as functions have been called and arrays have been indexed)
// Check that the variable is recognized..
2020-11-23 21:42:32 +00:00
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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
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 ;
}
2021-01-20 19:22:15 +00:00
/*
* Handles the surrounding logic for all of the logical and semantic
* prefixes .
*
* Prefixes are tokens that are affixed to the start of another , and
* change behaviour in some way . These can be added calculations ,
* some form of transformation , or other .
*
* A current list of prefixes :
* * ! : Invert the boolean result of a statement or truthy value .
* * ~ : Invert the individual bits in a number
* * - : Invert the number around the axis of 0 ( negative - > positive , positive - > negative )
* * + + : Increment a variable BEFORE it is returned .
* NOTE : there is a postfix variant of this for incrementing AFTER the fact .
* * - - : Decrement a variable BEFORE it is returned .
* NOTE : there is a postfix variant of this for decrementing AFTER the fact .
* * & : Dereference the following object ( Get the address that contains it )
* * * : Get the object pointed at by the number following
*
* Planned prefixes :
* * < < : Arithmetic - Shift - Left a variable by one ( Multiply by two )
* NOTE : there is a postfix variant of this for shifting right - dividing by two .
*
* @ return the AST of this statement , plus its ' prefixes and any postfixes .
*/
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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-11-23 21:42:32 +00:00
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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-11-23 21:42:32 +00:00
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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-11-24 13:17:01 +00:00
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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-11-23 21:42:32 +00:00
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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-11-23 21:42:32 +00:00
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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-09-13 01:26:49 +00:00
// 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 :
2021-01-20 19:22:15 +00:00
Tokenise ( ) ;
2020-09-13 01:26:49 +00:00
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
}