# data[].attributes.body
1. If statements create an if node in the AST. If conditions are viewed as params (this might change). The code that is within the if statement is added to the body of the if node. While statements create while nodes, the code inside a while statement is added as body in the while node and the conditions that allow the while node to continue running will be in the parameters of the while node. Most of the heavy lifting will be done with the optimizer and tac generation to make the if statements and while loops useful.

2. GOTO statements are currently not in use as most logic is folded by the optimizer, but the next thing we are doing is implementing it into MIPS for on the fly running without the need for it to be optimized ahead of time.

3. Complex if-else and while statements are handled by breaking everything down into nodes. Also parentheses are used to break up conditions if the programmer desires to increase clarity.

Code Snippet:

func parseIfStatement(tokens []string, lineNumber int) *Node {
	var newNode Node
	openParen := 0

	newNode.Type = "IF_STATEMENT"
	newNode.DType = "IF"

	if tokens[1] != "(" {
		fmt.Println("Expected \"(\" got " + tokens[1] + " on line " + strconv.Itoa(lineNumber))
		os.Exit(3)
	} else {
		openParen++
	}

	closeParenIndex := slices.Index(tokens, ")")

	if closeParenIndex == -1 {
		fmt.Println("Expected \")\" got " + tokens[2] + " on line " + strconv.Itoa(lineNumber))
		os.Exit(3)
	} else {
		openParen--
	}

	if closeParenIndex != 3 {
		conditions := tokens[2:closeParenIndex]

		ampersandIndex := slices.Index(tokens, "&")

		if ampersandIndex == len(conditions)-1 {
			fmt.Println("Invalid \"&\" usage! Line:", lineNumber)
			os.Exit(3)
		}

		pipeIndex := slices.Index(tokens, "|")

		if pipeIndex == len(conditions)-1 {
			fmt.Println("Invalid \"|\" usage! Line:", lineNumber)
			os.Exit(3)
		}

		for i := 1; i < (len(conditions) + 1); i += 3 {
			newNode.Params = append(newNode.Params, parseConditions(conditions[i:i+2], lineNumber))
		}
	}

# data[].attributes.body
1. The ASTs will be different because for an If statement if the condition is true the code in the statement is then run and then the code continues from there, but for While loops the code will have to jump back to the condition

2. We will have to make it so that the GOTO for Whiles will jump back to the top of the While loop

3. Currently, If statements don't have their own scope and require curly brackets around the code block to keep things simple. For the sake of simplicity, we will keep this same structure for While loops.

The image attached is our current grammar for Ifs and our grammar for While loops will likely be very similar to the way IfStmt looks.

# data[].attributes.body
1. Loops will only need conditional information and block info while the if statements also added a next for when if else statements were chained together

2. We will manage Goto statements by having custom tac before and after the body of the while statement

3. To handle complex IF/While statements, we compute the result of the condition before the conditional jump, this allows us to have complex conditional expressions in or IF and While statements

# data[].attributes.body
1. it would be similar if not identical

2. goto will be similar to if but instead of go to next line when done, it will loop back to the beginning until the condition is false

3. We planning to use labels to distinguish between components of the conditions

# data[].attributes.headline
Carlos Llanes, Jonathan Rivas, Kevin Tran

# data[].attributes.subject
Carlos Llanes, Jonathan Rivas, Kevin Tran

# data[].attributes.body
To add while loops, we’ll build on how we handle if statements. Both use ConditionList for parsing conditions and StmntList for the block of statements. While if ASTs include fields for branches like ElseIfList and ElseStmnt, the while AST will only need a condition and loop body, making it simpler. The node will be of type NodeType_WhileLoop, compared to NodeType_IfStmnt for if statements.

For TAC, while loops require labels and GOTO statements to enable looping. We’ll generate a label at the start of the loop for the condition, a conditional jump to exit the loop if false, and a GOTO back to the start after the body executes. An end label ensures the program continues correctly after the loop ends.

We’ll reuse ConditionList to manage complex conditions for while, just like we do for if. This includes logical operators like AND and OR and nested conditions. The TAC generation will evaluate these, making sure both constructs handle conditions consistently.

# data[].attributes.body
1. The ASTs will be different as while will have a goto at the bottom.

2. The goto will have us go back up to check the condition to see if we run the block of code again.

3. We will handle the long conditions with and/or in MIPS.

# data[].attributes.body
The IF statement AST has a condition boolean node and two child nodes, whereas the while has a condition node that is evaluated before each iteration and then a single child node that contains the starting point for the loop body. To manage goto statements, we are implementing labels to key points in the code, like the start of a loop or if statement. Complex ifs and whiles are managed with labels and breaking the conditions into smaller components and evaluating them separately.

# data[].attributes.attachment_link.readable_text
// Label generator
int labelCounter = 0;

char *generateLabel() {
    char *label = (char *)malloc(10);
    sprintf(label, "L%d", labelCounter++);
    return label;
}

// Emit function to output code
void emit(const char *code) {
    printf("%s\n", code);
}

// Generate code for IF statements
void generateIf(ASTNode *ifNode) {
    char *labelThen = generateLabel();
    char *labelElse = generateLabel();
    char *labelEnd = generateLabel();

    // Emit condition
    emit("IF NOT");
    emit(ifNode->condition->code);
    printf(" GOTO %s\n", labelElse);

    // Emit THEN block
    printf("%s:\n", labelThen);
    generateCode(ifNode->thenBlock);
    printf("GOTO %s\n", labelEnd);

    // Emit ELSE block (if exists)
    printf("%s:\n", labelElse);
    if (ifNode->elseBlock) {
        generateCode(ifNode->elseBlock);
    }

    // Emit END label
    printf("%s:\n", labelEnd);

    free(labelThen);
    free(labelElse);
    free(labelEnd);
}

void generateWhile(ASTNode *whileNode) {
    char *labelStart = generateLabel();
    char *labelEnd = generateLabel();

    // Emit start label
    printf("%s:\n", labelStart);

    // Emit condition
    emit("IF NOT");
    emit(whileNode->condition->code);
    printf(" GOTO %s\n", labelEnd);

    // Emit body
    generateCode(whileNode->body);

    // Jump back to start
    printf("GOTO %s\n", labelStart);

    // Emit end label
    printf("%s:\n", labelEnd);

    free(labelStart);
    free(labelEnd);
}

void generateCode(ASTNode *node) {
    if (!node) return;

    switch (node->type) {
        case NODE_IF:
            generateIf(node);
            break;
        case NODE_WHILE:
            generateWhile(node);
            break;
        case NODE_BLOCK:
            for (ASTNode *stmt = node; stmt != NULL; stmt = stmt->next) {
                generateCode(stmt);  // Recursively handle all statements in a block
            }
            break;
        case NODE_CONDITION:
            emit(node->code);  // Emit condition code directly
            break;
        default:
            fprintf(stderr, "Unknown AST node type!\n");
            exit(1);
    }
}

# data[].attributes.body
Create an AST for a SWITCH Statement

# data[].attributes.body
Suggest an AST for a simple IF and an AST for IF-ELSE using Bison and your AST.h and AST.c custom code (or similar)

# data[].attributes.body
Review the bulletpoints below and report your status - what have you addressed and how?

review all the changes necessary in the Lexer and add keywords, symbols as needed

review the use and structure of the symbol table (linked list of tables) and make necessary changes

review your prior decisions about variable declarations, i.e., where do you allow them to be defined

review your prior decisions about free standing statements

decide whether an IF-BLOCK has its own scope

decide on the appropriate structure of the AST representing an IF statement

add AST generation code to AST.h

update Bison with necessary rules to support IF and generate appropriate trees

adapt optimization techniques for expressions to optimizing th IF condition

adapt optimization techniques for function block, to IF block

# data[].attributes.body
Fully implement if-statements

# data[].attributes.body
Using the example as reference, write by hand the IR code you expect YOUR compiler to generate, for the following C- snippet:

If (a > b){

If (n > 0){

a = func1();

}

Write a;

Else {

Write b;

}

func1() {

Int x;

x = 25;

Return x;

}

# data[].attributes.attachment_link.readable_text
IR CODE for Functions
IR Code for complex mathematical expression
------------------------------------------------------------------
int res;

int AddNumbers (int x, int y){
	int res;
	res = x + y;
	return res;
}

res = AddNumbers(4,5);
write res;

---------------------- FUNCTION IR CODE --------------------------

// Prepare the parameters for the function
	P0 = 4
	P1 = 5
	Push L0 into stack of addresses
	GOTO AddNumbers
L0: Continue
	write R0  // must manage registers, don't simply assume it is R0; it could be R1
	Push L3 into stack of addresses
	GOTO SubtractNumbers
L3: Continue	
	write R0  // must manage registers, don't simply assume it is R0; it could be R1
	STOP
	
	// functions section
L1: AddNumbers 
	T0 = P0
	T1 = P1
        R0 = T0 + T1 //the result of addition
	GOTO Pop from stack of addresses

L2: SubtractNumbers 
	T0 = P0
	T1 = P1
        R0 = T0 - T1 //the result of subtraction
	GOTO Pop from stack of addresses

=============== REGISTER ALLOCATION ====================
Assume 3 families of registers (as an example):
T - for variables
P - for parameters
R - for function return values

Q: How to choose the correct/appropriate register (e.g., T0 vs T3)?
Q: What if we run out of registers?

           +++ Activity 1 +++
Assume there only 10 T registers, T0 - T9
Create an algorithm and implement so that:
 - create a mechanism for register allocation management
 - you keep track of register used
 - allocate the next available register
 - deallocate the current register when it is no longer used
 - write a library of functions to implement the above:
	- isRegisteInUse(r)
	- getNextAvailableRegister(r)
	- printRegistersStatus()
	- freeRegister(r)
	- etc.

          +++ Activity 2 +++
Create a mechanism for managing labels

================== MORE ON USE OF REGISTERS AN OPTIMIZATION ==================

x = 1 + 2/3 + 3 + 4*5;
T0 = 2/3
T1 = 4*5

T3 = 1 + T0 + 3 + T1
T4 = 3 + T1
T3 = 1 + T0 + T4
T5 = T0 + T4
T3 = 1 + T5

-------------------

x = (1 + 2/3 + 3 + 4*5)/(1 - 2 + 3);
T0 = 1 + 2/3 + 3 + 4*5
T1 = 1 - 2 + 3

z = 2 + 3 -6

x = (1 + 2/3 + z + 4*5)/(1 - z + 3);
T0 = 1 + 2/3 + 3 + 4*5
T1 = 1 - 2 + 3

NEW TOOL NEEDED: revise and re-write an expression

Your compiler must support expressions like:

int max(int a, int b){
    etc.
    return...
}


int min(int a, int b){
    etc.
    return...
}
z = 100
x = max(1,5)/min(56, z)

----------------------------------------------------------

Function call optimization:

Eliminate dead code, i.e. a function that was declared but never called
------------------------------------------------------
Division by zero detection:

x = 1/0

x = 1/(x-x)

---- CHALLENGE ----

x = 0
y = 1/x
write y

Can you detect before runtime?
Constant propagation provides the opportunity to detect divison by zero

Sometimes division by zero manifests only at runtime

x = min(myList)
y = 1/x

Challenge:

z = (1 + x - x + y - y -1)/(m + n - n - m)
Can you detect that the above is 0/0, regardless of values for x, y, m, n

------------- TRICKY OPTIMIZATIONS ---------------

z = x + x + x
z = 3*x

Z = max(list) + max(list) + max(list)
Z = 3*max(list) //potentially INCORRECT because you may want to execute max() 3 times.

Is it possible that performing the optimization takes longer than executing the unoptimized code?

Z = sort(myList) + sort(myList) // decide how to handle this, maybe differently depending on the return value

================= ADDING IF_STATEMENTS ============================

if (condition) {
	block
}
else {
	block
}
------------------------------------
write 1 > 0

bool x
x = 3 < y
write x

bool x
x = !(!(!(1 == 0)))


------------------------------------
Lexer:
  - add necessary keywords, and symbols (>, <, <=, ==, <=, !)
  - update lexical error messages

Parser:
   - AST
       * generate a tree for an IF statement

         if (a > b) {
	 	stmt1;  // e.g., assignment
		stmt1;  // e.g., function call
	 }

                   IF
              cond   block  

               
               >           block
             /  \         /     \
            a    b      null    stmt1
                               /     \
                              null   stmt2
                                       \
                                       etc.    

        * repeat the above for IF-ELSE

   - Symbol Table
       * nothing to add
       * consider using the ST as a helper, 
         e.g., values of variables tested in the IF condition: if (a > b)...etc.
   - Other

Semantic Analyzer
   - check if the variables in the condition are defined and of compatible types
   - decide whether type casting or coercion are necessary
   - review your approach to implementing boolean types
   - How would you handle the following?
         bool x;
         int y;
         y = 1;
         x = y + (2 > 1000);
         write x;

    - IR CODE
	* use temporary variables (aka "registers") to hold values of experessions in ()

 	if (a > b) {
	 	stmt1;  // e.g., assignment
		stmt1;  // e.g., function call
	 }

      ------ IR CODE -------
      T0 = a
      T1 = b
      if T0 <= T1 GOTO Continue
      stmt1
      stmt2
Continue

Optimizer
    - nothing much different than optimizing a block of a function
    - the IF condition, is an expression, which you already know how to optimize
    - if a condition is always FALSE, do not generate AST or IR code

Code Generator


=========== Activity 1 - Week 5 - Wed ============
   - review all the changes necessary in the Lexer and add keywords, symbols as needed
   - review the use and structure of the symbol table (linked list of tables) and make necessary changes
   - review your prior decisions about variable declarations, i.e., where do you allow them to be defined
   - review your prior decisions about free standing statements
   - decide whether an IF-BLOCK has its own scope
   - decide on the appropriate structure of the AST representing an IF statement
   - add AST generation code to AST.h
   - update Bison with necessary rules to support IF and generate appropriate trees
   - adapt optimization techniques for expressions to optimizing th IF condition
   - adapt optimization techniques for function block, to IF block

# data[].attributes.body
For example:

if ((a + b) > max(x,y)) {
z = a *b;
write z;
}
else {
z = 2 + m + q;
write z*2;
}

The Dangling ELSE Problem
-------------------------

IF ((a + b) > max(x,y)) {
IF (a>2 && b <100) {
z = a *b;
write z;
}
ELSE{
t = 100 * p;
write t;
}
}
ELSE{
IF (today == "m") {
callSomeFunction(today);
}
ELSE {
callAnotherFunction(0);
}
z = 2 + m + q;
write z*2;
}

======= IR CODE FOR IF-ELSE =========

IF (a > b) {
stmt1;  // e.g., assignment
stmt1;  // e.g., function call
}
ELSE {
addNumnbers(a,b);
}

------ IR CODE -------
T0 = a
T1 = b
if T0 <= T1 GOTO Continue1
stmt1
stmt2
GOTO Continue2
Continue1
P0 = a
P1 = b
PUSH Continue2
GOTO addNumbers
stop
Continue2
write R0
etc.
stop

addNumbers
T3 =
T4 =
R0 = T3 + T4
GOTO pop

# data[].attributes.body
------------------------ AST for IF-ELSE and nested IF ------------------

if (n > m) {
z = n - m;
write z;
}
else {
z = m - n;
write z;
}

write                   write
/     \                  /    \
=      null              =     null
/ \                      / \
z   -                    z   -
/ \                      / \
n   m                    m   n

\                     /
\                   /
\                 /

=
/  \
ifVar    >
/ \
n   m

----------------------------------------------------------------

write
/     \
=      null
/ \
z   \
T10
/   \
=      -
/  \    /  \
ifVar    >  n    m
/ \
n   m

------------------- IR Code for IF-ELSE -----------------

if (n > m) {
z = n * m - n/m;
write z;
}
else {
z = m - n;
write z;
}

T0 = n
T1 = m
T2 = n-m
IF T2 > 0 GOTO ELSEpart  //In Assembly: JPOS T2, ELSEpart
T3 = T0 * T1
T4 = T0/T1
T5 = T3 - T4
Output T5
GOTO Continue
ELSEpart: T3 = T1 - T0
Output T3
Continue  etc.

----------------- OPTIMIZING IF-STATEMENTS -------------------

- condition is an expression, so you optimize as an expression
- eliminate dead code
if (2 > 5) {
stmt1;
....
stmt20;
}
else{

}
- simplification of redundant statements (x + x + x --> 3*x)
- simplication of complex mathematical calculations:
x^3 --> x*x*x
- simplify nested if statements - VERY TRICKY
if (x > 0)
if (x < 10)
if (y >25) {
write r;
write '=';
write 100;
}

optimzed:
if (x>0 && x<10 && y>25){
write r;
write '=';
write 100;
}

------ ASSEMBLY CODE GENERATOR ----------

- lookup the various JUMP commands:
JMP, JNEG, JPOS, JZER
- Reminder: there are different categories of registers:
T - temporary variables
R - return results from functions
P - function arguments/parameters

MIPS has $v, $a, S$, etc.

# data[].attributes.body
Since we do not have it yet implemented in our compiler here is a simple layout of how our IF and IF-ELSE statements would work.

IF-Statement AST:

IfNode

/ \

Condition Body

IF-ELSE Statement AST:

IFNode

/    \

Condition    ELSE

/   \      /   \

Null  Block  Null  Block

Bison Incomplete code:

/* Add these tokens */

%token IF ELSE

%type <ast> if_statement else_statement condition_expression block_statement

statement

: /* existing rules */

| if_statement

{ $$ = $1; }

;

if_statement

: IF LPAREN condition_expression RPAREN LBRACE block_statement RBRACE

{

$$ = create_if_node($3, $6, NULL);

}

| IF LPAREN condition_expression RPAREN LBRACE block_statement RBRACE ELSE LBRACE block_statement RBRACE

{

$$ = create_if_node($3, $6, $10);

}

;

condition_expression

: expression

{ $$ = $1; }

;

block_statement

: statements

{ $$ = $1; }

;

AST.h incomplete:

ASTNode* create_if_node(ASTNode* condition, ASTNode* if_body, ASTNode* else_body);

AST.c incomplete:

ASTNode* create_if_node(ASTNode* condition, ASTNode* if_body, ASTNode* else_body) {

ASTNode* node = create_node("If", NULL);

node->left = condition;

node->middle = if_body;

field to ASTNode struct

node->right = else_body;

return node;

}

# data[].attributes.body
If:

If

/ \

Condition Block

Else-If:

If

/ \

Not Block

/ \

Condition null

Condition:

OP

/ \

ID ID

# data[].attributes.body
AST Generated:

└── Program [Type: PROGRAM, Value: ]

├── Declaration [Type: DECLARATION, DType: INT, Value: x]

│ └── Assignment [Type: ASSIGN, Value: =]

│ ├── Left:

│ │ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: x]

│ └── Right:

│ └── NUMBER [Type: NUMBER, DType: INT, Value: 10]

├── Declaration [Type: DECLARATION, DType: INT, Value: y]

│ └── Assignment [Type: ASSIGN, Value: =]

│ ├── Left:

│ │ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: y]

│ └── Right:

│ └── NUMBER [Type: NUMBER, DType: INT, Value: 5]

└── If Statement [Type: IF_STATEMENT, Value: ]

├── Condition:

│ └── GREATER_THAN [Type: GREATER_THAN, Value: >]

│ ├── Left:

│ │ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: x]

│ └── Right:

│ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: y]

├── Then:

│ └── Block [Type: BLOCK, Value: ]

│ ├── Declaration [Type: DECLARATION, DType: INT, Value: z]

│ │ └── Assignment [Type: ASSIGN, Value: =]

│ │ ├── Left:

│ │ │ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: z]

│ │ └── Right:

│ │ └── SUBTRACT [Type: SUBTRACT, Value: -]

│ │ ├── Left:

│ │ │ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: x]

│ │ └── Right:

│ │ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: y]

│ └── Function Call [Type: FUNCTION_CALL, Value: write]

│ └── Arguments:

│ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: z]

└── Else:

└── Block [Type: BLOCK, Value: ]

├── Declaration [Type: DECLARATION, DType: INT, Value: z]

│ └── Assignment [Type: ASSIGN, Value: =]

│ ├── Left:

│ │ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: z]

│ └── Right:

│ └── SUBTRACT [Type: SUBTRACT, Value: -]

│ ├── Left:

│ │ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: y]

│ └── Right:

│ └── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: x]

└── Function Call [Type: FUNCTION_CALL, Value: write]

└── Arguments:

└── IDENTIFIER [Type: IDENTIFIER, DType: INT, Value: z]

Parse code:

func parse(tokens []string, root Node) Node {

body := []*Node{}

for i := 0; i < len(tokens); i++ {

token := tokens[i]

switch token {

case "if":

// Parse the if statement

ifNode, newIndex := parseIfStatement(tokens, i, root)

body = append(body, ifNode)

i = newIndex - 1 // Adjust index since parseIfStatement advances it

// Existing cases...

}

}

root.Body = body

return root

}

func parseIfStatement(tokens []string, currentIndex int, root Node) (Node, int) {

i := currentIndex + 1 // Move past 'if'

// Expect '('

if tokens[i] != "(" {

fmt.Println("Expected '(' after 'if' on line", line)

os.Exit(3)

}

i++

// Find matching ')'

conditionEnd := findMatchingParen(tokens, i)

if conditionEnd == -1 {

fmt.Println("Unmatched '(' in if condition on line", line)

os.Exit(3)

}

// Parse condition expression

conditionTokens := tokens[i:conditionEnd]

conditionNode := parseGeneric(conditionTokens, line, root)

i = conditionEnd + 1 // Move past ')'

// Expect '{'

if tokens[i] != "{" {

fmt.Println("Expected '{' after if condition on line", line)

os.Exit(3)

}

i++

// Parse the 'then' body

thenBodyTokens, nextIndex := extractBlock(tokens, i)

thenNode := &Node{Type: "BLOCK", Body: parse(thenBodyTokens, root).Body}

i = nextIndex

// Check for 'else' clause

var elseNode *Node

if i < len(tokens) && tokens[i] == "else" {

i++

// Expect '{'

if tokens[i] != "{" {

fmt.Println("Expected '{' after 'else' on line", line)

os.Exit(3)

}

i++

// Parse the 'else' body

elseBodyTokens, nextIndex := extractBlock(tokens, i)

elseNode = &Node{Type: "BLOCK", Body: parse(elseBodyTokens, root).Body}

i = nextIndex

}

// Create the if statement node

ifNode := &Node{

Type: "IF_STATEMENT",

Condition: conditionNode,

Then: thenNode,

Else: elseNode,

}

return ifNode, i

}

This is hypothetical code for our compiler we are building in go

# data[].attributes.body
Bison:

IfStmt = IF LPAREN Condition RPAREN IfBlock Else {

$$->malloc(sizeof(ASTNODE))

//set node type to ifStmt

$3->ifStmt.condition

$5->ifStmt.block

$6->ifStmt.elseBlock

}

Else {//could be empty}

| ELSE IfBlock {

//set node type to else

$$->malloc(sizeof(ASTNODE))

$2->else.block

}

AST.h

typedef struct ASTNode {

NodeType type;

....

union {

struct{

struct ASTNode* condition;

struct ASTNode* block;

struct ASTNode* elseBlock;

} IfStmt;

AST:

If

Condition Else

Null. Block. NULL

If

Block. Condition

Null. NULL. Block

# data[].attributes.body
IF

/    \

/      \

Condition    ELSE

/   \      /   \

Null  Block  Null  Block

IF

/    \

/      \

Condition    Null

/   \

Null  Block

# data[].attributes.body
IF

├─ Condition

│ └─ Expression

├─ Statement is True

│ └─ Block

└─ Statement is False

└─ Block

Parser starter code for IF:

statement:

IF LPAREN condition RPAREN LBRACE statement RBRACE

| IF LPAREN condition RPAREN LBRACE statement RBRACE ELSE LBRACE statement RBRACE

;

condition:

Expr EQUALS Expr

| Expr GREATER Expr

| Expr LESS Expr

;

# data[].attributes.body
Here is a basic structure with some syntax for bison grammar, and sudo code used to represent our idea.

// AST Node Structure and Creation Functions

define ASTNode with properties:

- type (IF, IF_ELSE, CONDITION, BODY)

- condition (pointer to condition node)

- thenBody (pointer to then body node)

- elseBody (pointer to else body node, for IF-ELSE)

function createIfNode(condition, thenBody):

create node of type IF

set node.condition = condition

set node.thenBody = thenBody

return node

function createIfElseNode(condition, thenBody, elseBody):

create node of type IF_ELSE

set node.condition = condition

set node.thenBody = thenBody

set node.elseBody = elseBody

return node

// Bison Grammar Rules

program:

statement { root = $1 } // Start AST with the root node

statement:

'IF' condition body { $$ = createIfNode($2, $3) }

| 'IF' condition body 'ELSE' body { $$ = createIfElseNode($2, $3, $5) }

condition:

'condition_expr' { $$ = createConditionNode() }

body:

'body_statements' { $$ = createBodyNode() }

// Parsing and Error Handling

main():

parse input with yyparse()

process AST starting at root

error:

print "Syntax error"

# data[].attributes.body
The code provided uses a combination of pseudocode and bison syntax to represent our idea.

// AST Node Structure and Creation Functions

define ASTNode with properties:

- type (IF, IF_ELSE, CONDITION, BODY)

- condition (pointer to condition node)

- thenBody (pointer to then body node)

- elseBody (pointer to else body node, for IF-ELSE)

function createIfNode(condition, thenBody):

create node of type IF

set node.condition = condition

set node.thenBody = thenBody

return node

function createIfElseNode(condition, thenBody, elseBody):

create node of type IF_ELSE

set node.condition = condition

set node.thenBody = thenBody

set node.elseBody = elseBody

return node

// Bison Grammar Rules

program:

statement { root = $1 } // Start AST with the root node

statement:

'IF' condition body { $$ = createIfNode($2, $3) }

| 'IF' condition body 'ELSE' body { $$ = createIfElseNode($2, $3, $5) }

condition:

'condition_expr' { $$ = createConditionNode() }

body:

'body_statements' { $$ = createBodyNode() }

// Parsing and Error Handling

main():

parse input with yyparse()

process AST starting at root

error:

print "Syntax error"

# data[].attributes.headline
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.subject
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.body
IF:

NodeType_IfStmnt:

Condition: ...

VarDeclList: ...

StmntList: ...

Else: {} (empty/null for lone ifs)

IF-ELSE:

NodeType_IfStmnt:

Condition: ....

VarDeclList: ...

StmntList: ....

NodeType_Else:

VarDeclList: ...

StmntList: ....

Our initial thought is for ifs to have a condition, VarDeclList, StmntList, and an Else. For if statements the else would be empty/NULL an for if-else statements the else would be filled with another

# data[].attributes.body
IF

├── CONDITION

| └── [Condition Expression Node]

└── THEN

└── [Then Statement Node]

IF

├── CONDITION

| └── [Condition Expression Node]

└── THEN

| └── [Then Statement Node]

└── ELSE

└── [Else Statement Node]

# data[].attributes.body
IF:

IF

/ \

Condition Block

/ \

NULL Block

IF ELSE:

IF

/ \

Condition ELSE

/ \ / \

NULL Block NULL Block

IF ELSE-IF:

IF

/ \

Condition ELSE-IF

/ \ / \

NULL Block Condition Block

/ \ \

NULL Block ELSE-IF

/ \

Condition Block

/ \

NULL ELSE

/ \

NULL Block

# data[].attributes.body
This is what we were thinking of implement

# data[].attributes.body
IF

├─ Condition

│ └─ Expression

├─ Statement is True

│ └─ Block

└─ Statement is False

└─ Block

Parser starter code for IF:

statement:

IF LPAREN condition RPAREN LBRACE statement RBRACE

| IF LPAREN condition RPAREN LBRACE statement RBRACE ELSE LBRACE statement RBRACE

;

condition:

Expr EQUALS Expr

| Expr GREATER Expr

| Expr LESS Expr

;

# data[].attributes.body
Global Variable Declarations

Functions

Statements

---------------------------------

Global Variable Declarations

Functions

Main Function

----------------------------------

Global Variable Declarations

Statements

Functions

Statements

More Global Variable Declarations

Statements

etc.

---------------------------------

WHAT ABOUT BLOCKS?

function block

if block

while block

global block (outside a function)

-----------------------------

FuncDecl: TYPE ID (PARAMLIST) FuncBlock

FuncBlock: { VarDeclist StatementsList Return}

vs.

FuncDecl: TYPE ID (PARAMLIST) {Block Return }

Block: { VarDeclist StatementsList }

------------------------------------------

Stmt: AssgnStmt | IfStmt | WhileStmt | WriteStmt...

IfStmt: IF ( Condition ) Block

Block: VarDeclList StmtList | StmtList

WhileStmt: WHILE ( Condition ) Block

Block: VarDeclList StmtList

----------------------------------

What if you don't allow VarDecl inside IF or While?

IfStmt: IF ( Condition ) {StmtList}

WhileStmt: WHILE ( Condition ) {StmtList }

# data[].attributes.headline
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.subject
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.body
NodeType_SwitchStmt:

Condition: ...

CaseList: ...

Default: {} (empty/null if no default case)

typedef struct Case {

int value;

ASTNode* stmntList;

} Case;

typedef struct CaseList {

Case* caseNode;

struct CaseList* caseList;

} CaseList;

typedef struct SwitchStatement {

ASTNode* condition;

CaseList* caseList;

ASTNode* defaultStmt;

} SwitchStatement;

# data[].attributes.body
We are still trying to fix a final error with the arrays, but we have started determining what our grammar for if and else statements will look like:

# An if statement with an optional else statement.

IfStmt: IF LPARA Condition RPARA Block ElseStmt {}

# An optional else statement can be empty or contain an else block.

ElseStmt: (null) {}

| ELSE Block {}

# A condition that needs to be met

Condition: Value {}

| Value COMPARISON Value {}

| LPARA Condition RPARA LOGIC_OPERATOR LPARA Condition RPARA {}

# data[].attributes.body
// AST.h

typedef enum { NODE_IF, NODE_IF_ELSE, NODE_EXPR, NODE_STMT } NodeType;

// Base AST Node

typedef struct ASTNode {

NodeType type;

struct ASTNode* left; // Left child

struct ASTNode* right; // Right child

} ASTNode;

// If Statement (if <condition> <then-branch>)

typedef struct {

NodeType type;

ASTNode* condition; // Condition expression

ASTNode* thenBranch; // Then branch statement

} IfStmt;

// If-Else Statement (if <condition> <then-branch> else <else-branch>)

typedef struct {

NodeType type;

ASTNode* condition; // Condition expression

ASTNode* thenBranch; // Then branch statement

ASTNode* elseBranch; // Else branch statement

} IfElseStmt;

// Function prototypes

ASTNode* createIfStmt(ASTNode* condition, ASTNode* thenBranch);

ASTNode* createIfElseStmt(ASTNode* condition, ASTNode* thenBranch, ASTNode* elseBranch);

void freeAST(ASTNode* node);

# data[].attributes.body
For now, we are still working on optimizing the optimization for functions, so in order to not make that harder, we will not add functions until that is done.

Considerations:

No free standing statements in our language.

Variable declarations are at the top of the block before the expressions.

IF Block does not have its own scope

AST for IF Statement:

IF

├─ Condition

│ └─ Expression

├─ Statement is True

│ └─ Block

└─ Statement is False

└─ Block

Parser starter code for IF:

statement:

IF LPAREN condition RPAREN LBRACE statement RBRACE

| IF LPAREN condition RPAREN LBRACE statement RBRACE ELSE LBRACE statement RBRACE

# data[].attributes.body
If:

If

/ \

Condition Block

Else-If:

If

/ \

Else Block

/ \

Condition null

# data[].attributes.headline
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.subject
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.body
We're still working on the code generation of the previous milestone so we haven't made any progress on IFS.

Considerations:

Various tokens need to be added such as ||, &&, = >, =<, if, else, etc.

We don't anticipate any changes to the symbol table

Variable declaration will be allowed in function declarations and after function declarations

statements will only be allowed after variable declarations and in IFS

an IF block will not have its own scope

AST for IFS

IF:

NodeType_IfStmnt:

|______Condition: ...

|______VarDeclList: ...

|______StmntList: ...

|______Else: {} (empty/null for lone ifs)

IF-ELSE:

NodeType_IfStmnt:

|______Condition: ....

|______VarDeclList: ...

|______StmntList: ....

|______NodeType_Else:

|________________VarDeclList: ...

|________________StmntList: ....

# data[].attributes.body
We are currently working on making final touches to our function and arrays. But in the meantime this is our approach towards the IF statements as of now is like this

%{

#include "AST.h"

%}

%union {

ASTNode* node;

}

%token IF ELSE

%type <node> stmt expr if_stmt if_else_stmt

%%

stmt:

if_stmt

| if_else_stmt

;

if_stmt:

IF '(' expr ')' stmt {

$$ = createIfStmt($3, $5);

}

;

if_else_stmt:

IF '(' expr ')' stmt ELSE stmt {

$$ = createIfElseStmt($3, $5, $7);

}

;

expr:

// Define expression rules here that return ASTNode* for expressions

;

# data[].attributes.body
Here's the decisions we have for our if-else, we would be putting them inside of the statement so that It would be able to go wherever the statement is allowed to go. We believe this would be the best course of action. Still the branch jumping for the IR and the MIPS would be our biggest problem

# data[].attributes.body
After discussion, we have decided that if blocks do not have their own scope. this would require rearranging our grammar from the top.

We are still working on finalizing the code generation and optimization of functions

# data[].attributes.body
Micheal and I have still been working on trying to finish implementing arrays and functions. We have our TAC almost completely finished and we have begun our optimization. All that we have left to do is finish our optimization and code generation and then we will begin to work on the logical expressions. When we work on logical expressions, we will need to adjust many of our parser rules to recognize logical statements and we will have to address those before expressions so that we can correctly handle the order of operations for those logical checks.

# data[].attributes.body
Here is our complete ast for our most complex functionality:

Abstract Syntax Tree (AST):

Program

Function Definition: add, Return Type: int

Parameters:

Param: a, Type: int

Param: b, Type: int

Param: c, Type: int

Block:

Assignment: x

Number: 25

Assignment: result

Binary Operation: +

Identifier: a

Binary Operation: *

Identifier: b

Number: 9

Write Statement: x

Return Statement

Identifier: result

Function Definition: test, Return Type: int

Parameters:

Param: value, Type: int

Block:

Variable Declaration: result, Type: int

If Statement:

Condition:

Binary Operation: <

Identifier: value

Number: 10

If Body:

Assignment: result

Number: 1

Write Statement: result

Else If Statement:

Condition:

Binary Operation: ==

Identifier: value

Number: 10

Else If Body:

Assignment: result

Number: 2

Write Statement: result

Else Statement:

Assignment: result

Number: 3

Write Statement: result

If Statement:

Condition:

Binary Operation: &&

Binary Operation: >

Identifier: value

Number: 5

Binary Operation: <

Identifier: value

Number: 15

If Body:

Assignment: result

Number: 4

Write Statement: result

Return Statement

Identifier: result

Main Function: main

Block:

Assignment: sum

Function Call: add

Argument List:

Arg:

Number: 6

Arg:

Number: 3

Arg:

Number: 9

Array Declaration: arr, Type: int

Array Sizes:

Initializer:

Assignment:

Number: 10

Number: 20

Number: 30

Number: 40

Number: 50

Number: 60

Number: 70

Assignment: x

Number: 25

Write Array Element: arr

Number: 4

Write Statement: sum

Function Call: test

Argument List:

Arg:

Number: 4

Function Call: test

Argument List:

Arg:

Number: 10

Function Call: test

Argument List:

Arg:

Number: 20

Return Statement

Number: 0

# data[].attributes.body
main = (null) function (null)

# First IF condition: if (a > b)

t0 = a > b cmp (null)

t0 = false goto else_1

# Nested IF condition: if (n > 0)

t1 = n > 0 cmp (null)

t1 = false goto ifEnd_1

# Inside inner IF: a = func1()

t2 = func1 call (null)

a = t2 assign (null)

# Write a

ifEnd_1 = (null) contBranch (null)

write = a output (null)

# Else condition: Write b

else_1 = (null) elseBranch (null)

b = (null) write (null)

# Function definition for func1

func1 = (null) function (null)

x = 25 assign (null)

x =(null) return (null)

exit = (null) exit (null)

# data[].attributes.body
Func1:

T7 = 25

T0 = T7

GOTO CONTINUE2

Main:

T0 = a

T1 = b

T2 = T0 - T1

IF T2 <= 0

Output T1

GOTO CONTINUE1

T3 = n

T4 = 0

T5 = T3 - T4

IF T5 >= 0

GOTO Func1

CONTINUE2

Output T0

GOTO CONTINUE1

CONTINUE1 Output End

# data[].attributes.body
# Function func1 definition

func1:

t0 = 25

x = t0

return x

# Main control flow

t1 = a > b

if_false t1 goto L1

t2 = n > 0

if_false t2 goto L2

t3 = call func1, 0

a = t3

L2:

print a

goto L3

L1:

print b

L3:

# data[].attributes.body
arg declare

func addTwoNums

a0 param a

a1 param b

result declare

t2 = t0 + t1

result = t2

return result

func main

x declare

arr array, size 5

arr[3] = 2

t3 = arr[3]

x = t3

write x

return 0

arg = 1

# data[].attributes.body
t1 = a > b

t2 = n > 0

t3 = call func1

a = t3

t4 = a

t5 = b

// Pseudo-code to represent conditional writes

if t1 == true:

if t2 == true:

a = t3

call write(t4)

else:

call write(t5)

func func1:

x = 25

return x

end func

# data[].attributes.body
(Assuming that `a`, `b`, and `n` are of type int)

IR for main:

i0 = a store.int (null)

i1 = b store.int (null)

i2 = i0 >.int i1

(null) = i2 startIf (null)

i3 = 0 assign.int (null)

i4 = n <.int 0

(null) = i4 startIf (null)

(null) = func1 funcCall (null)

a = returnInt store.int (null)

(null) = (null) endIf (null)

i5 = a store.int (null)

(null) = i5 write.int (null)

(null) = (null) endIf (null)

(null) = (null) startElse (null)

i6 = b store.int (null)

(null) = i6 write.int (null)

(null) = (null) endElse (null)

IR for func():

(null) = (null) functionStart (null)

x = 25 assign.int (null)

returnInt = x store.int (null)

(null) = (null) return (null)

# data[].attributes.body
if a > b goto L1

goto L2

if n > 0 goto

goto L5

t1 = call func1

a = t1

goto L5

write a

goto L3

func func1

x = 25

return x

endfunc

# data[].attributes.body
start:

if a > b goto if1

goto else1

if1:

if n > 0 goto if2

goto write_a

if2:

t1 = func1()

a = t1

goto write_a

write_a:

write a

goto end

else1:

write b

goto end

func1:

t2 = 25

return t2

end:

# data[].attributes.body
Main:

t0 = a

t1 = b

if(t0 > t1)

goto ifStatement1

else

print t0

ifStatment1:

t0 = n

if(n > 0)

goto ifStatement2

ifStatement2:

t0 = call func1

func1:

t0 = x

x = 25

return x

# data[].attributes.body
t1 = x > 5

if t1 goto L1

goto L2

L1:

x = x + 1

goto L3

L2:

x = x - 1

L3:

# data[].attributes.body
We have addressed all the points in our compiler project and made significant progress. We updated the lexer to include new keywords and symbols needed for arrays and `if/else` statements, ensuring that the language syntax is correctly recognized during the lexical analysis phase. This involved adding tokens for conditional statements, array indexing, and other operators to handle the new syntax elements effectively.

We enhanced the symbol table by implementing a linked list structure that supports scopes, which allows for proper variable declaration and resolution within their respective scopes, including nested blocks like functions and `if` statements. This hierarchical symbol table ensures that variables are correctly scoped and prevents naming conflicts across different parts of the program.

We reviewed our prior decisions about where variable declarations are allowed and decided to permit them in appropriate places such as within `if` blocks, which now introduce their own scopes. This flexibility allows for cleaner and more intuitive code, as variables can be declared closer to where they are used.

We updated the Abstract Syntax Tree (AST) to accurately represent `if` statements by adding the necessary node structures to reflect the conditional logic in the program. Additionally, we added AST generation code to handle these new structures effectively, ensuring that the parser builds the correct tree representation of the program's flow.

We modified the parsing rules to support `if` statements, ensuring that the parser generates appropriate AST nodes for them. This included handling the parsing of conditional expressions and block statements within the `if` and `else` branches. We also made sure that the parser correctly manages nested `if` statements and scopes.

Finally, we adapted optimization techniques that were previously applied to expressions and function blocks so that they also optimize `if` conditions and `if` blocks. This has improved the overall efficiency of the compiler by reducing unnecessary computations and simplifying control flow where possible. We implemented constant folding and dead code elimination within conditional statements to enhance performance.

Overall, these changes have significantly enhanced our compiler's capabilities, allowing it to handle more complex language features while maintaining efficient performance. We are confident that these updates will provide a solid foundation for further development and support for additional language constructs in the future.

# data[].attributes.body
Post team updates:

1. Are you done with functions?

2. Have you started to work on if-statements?

# data[].attributes.body
1. Yes

2. Yes

# data[].attributes.body
1. Only need to fix a few bugs, and finish optimizer.

2. Planning to start over the weekend.

# data[].attributes.body
working on adding functionality of the current functions all teh way tot eh optimiser

# data[].attributes.body
1. No

2. No

# data[].attributes.headline
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.subject
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.body
1. We are done with TAC for function, working on generating code for it

2. We have started on AST for if statements, we will be working on semantic to generate TAC for it

# data[].attributes.body
1. Yes

2. Working on the boolean for now

# data[].attributes.body
1. No but close

2. Kind of

# data[].attributes.body
1. Yes

2. Yes

# data[].attributes.body
1. On Code generation. TAC is all done

2. No.

# data[].attributes.body
1. Yes, we are done with functions.

2. Yes, we have started work on if-statements.

# data[].attributes.body
1. No

2. No

# data[].attributes.body
1. Yes fully done

2. Yes creating the TAC for it

# data[].attributes.body
1. We need to finish arrays

2. We have started planning out how we want to approach if statements

# data[].attributes.body
Post a code snippet and screenshots of execution showing your compiler handling:

simple if-statement

if-else statement

nested if-statement

For example:

if (x == 5){

   doSomething();

}

-----------------------

if (x > 1 && x < 10} {

    doSomething();

}

else {

    doSomethingElse();

}

---------------------------

if (!(b > 0)) {

    if (n > 100) {

        doThis();

    }

    else {

         if (c == 10) {

             doThat();

          }

    }

}

# data[].attributes.body
lexer

AST for IF and its variations

syntax validation

Semantic validation

Produce TAC

Optimize IF (e.g. remove unreachable code)

Generate Assembly

# data[].attributes.body
We haven't fully connect the == and the !, but the other should be working, andn we got our if-else up to the AST, with it being able to handle simple if, if-else, and nested if:

if(test)

{ if(anotherTest)

{ x = 2; }

} else

{ x = 3; }

write x;

# data[].attributes.body
When running simple if statements it goes through it fully yet it still goes through even if the condition is false, as for other statements it does not work

# data[].attributes.body
We're still working on fixing bugs with parameters, but this is our plan for the compiler handling if statements with the AST.

if x > 0:

if y > 0:

z = 1

else:

z = -1

else:

z = 0

# data[].attributes.body
We have our If statements working up until the optimized tac. We are still working on code generation and being able to compare floats.

# data[].attributes.headline
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.subject
Jonathan Rivas, Kevin Tran, Carlos Llanes

# data[].attributes.body
We have if, elif, and if else working up to the AST

# data[].attributes.body
Still working on this...

# data[].attributes.body
AST can handle if statements and relational operators, but semantic and beyond do not have these features implemented. The AST in the screenshot was generated from the collowing code:

int x;

int y;

x = 10;

if (x > 0) {

y = 4;

if (y > 4)

{

write y;

}

else

{

write x;

}

}

# data[].attributes.body
Yes

Yes

# data[].attributes.body
Still working on the AST, just started with the lexer for the if statements

# data[].attributes.body
We currently have the lexer and are working on the parser/ast.

# data[].attributes.body
So far we have basic if-statements, if-else, if-else if- else statement working in the code gen

# data[].attributes.body
Still working on implementation of if statements

# data[].attributes.body
1. Yes

2. Yes

# data[].attributes.body
Not all of you have demonstrated working if-statements on Wednesday.

Update your post on if, and repost today, demonstrating a more complete and debugged implementation

# data[].attributes.body
Have completed if statements up to the AST and Symbol Table

Formatted Output:

Global Scope (Level 0):

Function main with return type void

Function getX with return type int

Function getY with return type int

Scope Level 1 (main):

Variable result of type int

Variable flag of type bool

Scope Level 1 (getX):

Parameter value of type int

# data[].attributes.body
IF statements and nest if statements work!!Raw Line: "int x = 10"

Tokens: [int x = 10

]

Raw Line: "int y = 5"

Tokens: [int y = 5

]

Raw Line: ""

Tokens: [

]

Raw Line: "if (x > 0) {"

Tokens: [if ( x > 0 ) {

]

Raw Line: " if (y > 0){"

Tokens: [if ( y > 0 ) {

]

Raw Line: " write(y)"

Tokens: [write ( y )

]

Raw Line: " }else{"

Tokens: [} else {

]

Raw Line: " write(x)"

Tokens: [write ( x )

]

Raw Line: " }"

Tokens: [}

]

Raw Line: "}else{"

Tokens: [} else {

]

Raw Line: " write(0)"

Tokens: [write ( 0 )

]

Raw Line: "}"

Tokens: [}

]

Parsing...

Finished Parsing! Beginning Optimization...

Finished Optimization! Outputting Tac...

Tac Complete! Compiling to MIPS...

MIPS code has been written to output.mips

Finished! 【=◈ ︿ ◈=】

int x = 10

int y = 5

if (x > 0) {

if (y > 0){

write(y)

}else{

write(x)

}

}else{

write(0)

}

# data[].attributes.body
Here is some of the code that we have for if statements for our AST implementation.

# data[].attributes.attachment_link.readable_text
typedef struct ASTNode {
    NodeType type;
    union {
        struct {
            struct ASTNode* functionDefList;
            struct ASTNode* varDeclList;
            struct ASTNode* stmtList;
        } program;

        struct {
            struct ASTNode* functionDef;
            struct ASTNode* functionDefList;
        } functionDefList;

        struct {
            char* name;
            struct ASTNode* varDeclList;
            struct ASTNode* stmtList;
        } functionDef;

        struct {
            char* name;
        } functionCall;

        struct {
            struct ASTNode* varDecl;
            struct ASTNode* varDeclList;
        } varDeclList;

        struct {
            char* varType;
            char* varName;
        } varDecl;

        struct {
            int integer;
        } IntExpr;

        struct {
            float floatNum;
        } FloatExpr;

        struct {
            char* name;
        } simpleID;

        struct {
            char* operator;
            struct ASTNode* left;
            struct ASTNode* right;
        } expr;

        struct {
            struct ASTNode* stmt;
            struct ASTNode* stmtList;
        } stmtList;

        struct {
            char* id;
        } writeStmt;

        struct {
            char* varName;
            char* operator;
            struct ASTNode* expr;
        } assignStmt;

        struct {
            char* varType;
            char* varName;
            int size;
        } arrayDecl;

        struct {
            char* arrayName;
            struct ASTNode* index;
        } arrayAccess;

        // New structures for if statements
        struct {
            struct ASTNode* condition;
            struct ASTNode* thenBlock;
        } ifStmt;

        struct {
            struct ASTNode* condition;
            struct ASTNode* thenBlock;
            struct ASTNode* elseBlock;
        } ifElseStmt;
    };
} ASTNode;


		case NodeType_IfStmt:
            printIndent(level + 1);
            printf("Condition:\n");
            traverseAST(node->ifStmt.condition, level + 2);
            printIndent(level + 1);
            printf("ThenBlock:\n");
            traverseAST(node->ifStmt.thenBlock, level + 2);
            break;

        case NodeType_IfElseStmt:
            printIndent(level + 1);
            printf("Condition:\n");
            traverseAST(node->ifElseStmt.condition, level + 2);
            printIndent(level + 1);
            printf("ThenBlock:\n");
            traverseAST(node->ifElseStmt.thenBlock, level + 2);
            printIndent(level + 1);
            printf("ElseBlock:\n");
            traverseAST(node->ifElseStmt.elseBlock, level + 2);
            break;

# data[].attributes.body
We still are facing an issue where the code generator outputs code within an if statement that is false when its only supposed to when its true

# data[].attributes.headline
Jonathan Rivas, Carlos Llanes, Kevin Tran

# data[].attributes.subject
Jonathan Rivas, Carlos Llanes, Kevin Tran

# data[].attributes.body
In the same spot as Wednesday, just starting the TAC for ifs

# data[].attributes.body
Current AST for IF statements

# data[].attributes.body
So far we have basic if-statements, if-else, if-else, and if-else statements working in the code gen. Now we are working on the optimizer.

# data[].attributes.body
Parser and AST done for IF

# data[].attributes.body
Today we submitted our functions and arrays so we did not start on if yet

# data[].attributes.body
We have the AST tree for the if-else, nested if and everything, we are planning to work on the TAC next

# data[].attributes.body
This is the current progress of our compiler. We have not made it to semantic analysis yet.

# data[].attributes.body
Explain your adaptation of the code used to implement IF statements, to WHILE statements.

1. How are the ASTs different?

2. How do you manage GOTO statements?

3. How are you handling complex IF/WHILE conditions?

Show the code snippets that illustrate the above

# data[].attributes.body
1. The ASTs honestly shouldn't look different honestly as the AST is just the structure of the code and they both are just the name of the token and block of code underneath. The only difference is a while loop might have the goto to repetively call it.

2. We will manage goto by having that in the AST most likely which can then check the condition again to see if while needs to run.

3. Im assuming this is talking about multiple conditions which we havent dealt with completely but MIPS has built in and or so we should be fine

# data[].attributes.body
Confirm that the following are complete:

Function parsing, AST, semantic analysis, Assembly

IF-Statements parsing, AST, semantic Analysis, Assembly

Started to implement WHILE-statements