# data[].attributes.body
All we have left is tac and code generation

# data[].attributes.body
Only TYPE_INT supported. All variables and expressions are integers. Simple type checking: int + int;  ( = int). The reason is because it is easy to implement and debug.  Type Checking Process: Lookup operands in symbol table → both TYPE_INT,  Check compatibility → int + int valid & Return result type → TYPE_INT

2. ERROR INSIGHTS TO PROGRAMMERS:

Three-Level Detection:

-          Lexical Errors: "LEXICAL ERROR at Line 2, Col 9: Unrecognized character '@'" - Shows exact location and invalid character.

-          Syntax Errors: Visual box format shows line/column, what was found vs. expected: "unexpected ID, expecting SEMICOLON"

-          Semantic Errors: "Line 3: Variable 'x' used before declaration" - Clear, actionable message.

# data[].attributes.body
Debugging syntax errors with print statements:

# data[].attributes.body
1. TBD, currently only handles int.

2. Compiler currently returns default error messages such as line number when a syntax error occurs

# data[].attributes.body
Added new TAC operations for functions (TAC_FUNCTION_START, TAC_FUNCTION_END, TAC_PARAM, TAC_CALL, TAC_RETURN, TAC_LABEL)

Implemented function support in TAC generation:

Added handling for function declarations (generates function start/end labels)

Added handling for function calls (generates PARAM and CALL instructions)

Added return statement support

Fixed the warning (added missing switch cases for TAC_SUB, TAC_MUL, TAC_DIV, etc.)

Updated print functions to display the new operations

Implemented MIPS code generation for functions:

Function declarations: generates prologue/epilogue, manages stack frame, saves $ra and $fp

Function calls: loads arguments into $a0-$a3, uses jal instruction, retrieves return value from $v0

Return statements: moves value to $v0, jumps back with jr $raparser.y - Fixed grammar to allow mixing statements and functions in any order (changed unit from stmt_list to stmt)

# data[].attributes.body
Working on CodeGen

TBD, but likely allow type coercion with ints to floats and throw errors for vice-versa

TBD, but like with number two, plan on including information to help debug

# data[].attributes.body
Finished function support

# data[].attributes.body
Added structure node for functions in syntax

# data[].attributes.body
Currently I am working on GETTING multiple types such as floats. I am not sure if I have good error handling yet, so that could be the next step.

# data[].attributes.body
Functions currently compile and generate correct MIPS code.

Handle expressions with multiple types by casting variables to floats type and warning the user

Program dedicated to generate accurate and useful errors, giving suggestions

# data[].attributes.body
It successfully compiles with functions

# data[].attributes.body
Still getting errors on adding Functions.

# data[].attributes.body
Compiler has implemented functions, if-statements, and loops along with a few other typical features

# data[].attributes.body
Provide an update with a screenshots of the current status of function implementation

Explain how do you handle expressions with multiple types

Explain how your compilers provides useful insights to programmers when errors occur

NOTE: I encourage you to complete the the current assignment and submit this weekend, so we can move on with if-statements

# data[].attributes.body
Added function support in parser

Updated the AST structure

Implemented function call return handling

Added TAC support for function declarations, calls and return statements

Added scope management

# data[].attributes.body
Extended Symbol Table (symtab.h/c):
Added hierarchical scoping system using pushScope() and popScope().
Implemented support for function entries (isFunction, paramCount, returnType) and local variable tracking.
Integrated addFunction() and lookupInScope() for resolving function and variable declarations.

Expanded AST (ast.h/c):
Added node kinds for NODE_FUNC_DECL, NODE_FUNC_CALL, NODE_PARAM, NODE_RETURN, and NODE_BLOCK.
Implemented constructors createFuncDecl(), createFuncCall(), and createReturn() with type handling.
Updated printAST() for full function and return visualization.

Updated Parser (parser.y):
Extended grammar for function declarations, parameter lists, return statements, and array access.
Added productions for complex expressions and return validation within function bodies.
Verified syntax with test programs including nested expressions and multi-parameter functions.

Enhanced Lexer (scanner.l):
Added tokens for void, return, and brackets {}.
Verified correct token stream output for test functions.

Semantic Checks (ast.c):
Added checks for undeclared identifiers, return type mismatches, and array bounds.
Ensured function parameters match declared count and types.
Implemented return enforcement for non-void functions.

TAC Extension (tac.h/c):
Added new TAC opcodes: FUNC_BEGIN, FUNC_END, CALL, PARAM, and RETURN.
Implemented TAC emission for function declarations and calls with parameter passing.
Added OPT_VERBOSE flag for debugging optimized TAC output.

Code Generation (codegen.c):
Implemented MIPS prologue/epilogue and register management for $a0–$a3, $v0, and $ra.
Added MIPS output for CALL and RETURN sequences.
Verified output for sample function int add(int a, int b) { return a + b; }.

Benchmarking & Testing:
Retained CPU/Wall time metrics from Performance Phase.
Added tests for simple and nested function calls with local arrays.
Confirmed valid TAC and MIPS output during compilation.

# data[].attributes.attachment_link.readable_text
Implemented grammar rules in Bison for:
• Function declarations (with and without parameters)
• Function calls and return statements
• Support for parameter lists and argument passing

Updated lexer to return new tokens:
• FUNCTION, RETURN, LPAREN, RPAREN, COMMA
• No major restructuring existing tokenization handles most keywords

Symbol Table & Scope Management:
• Extended symtab.c and symtab.h to handle nested scopes
• Added new fields for function tracking: isFunction, returnType, paramCount, scopeLevel, funcContext
• Implemented scope stack system using pushScope() and popScope()
• Local variables and parameters are registered under each function scope

AST Additions:
• Added NODE_FUNC_DECL, NODE_FUNC_CALL, NODE_PARAM_DECL, NODE_RETURN to ast.h
• Functions store parameter lists and statement blocks in AST structure

Semantic Checks:
• Verify variable scope, parameter count, and type match
• Ensure return type matches declared function type
• Detect mismatches in complex expressions
• Supports 'return x' and 'return a + b'; rejects 'return void'

TAC Generation:
• Added TAC_FUNC_BEGIN, TAC_FUNC_END, TAC_PARAM, TAC_CALL, TAC_RETURN, TAC_ARG
• Generates TAC such as:
  FUNC_BEGIN add
  PARAM a
  PARAM b
  t0 = a + b
  RETURN t0
  FUNC_END add

Optimizer Enhancements:
• Added constant folding, propagation, and dead code elimination
• Removes unused temporaries and redundant computations

Code Generation (MIPS):
• Generates function prologue and epilogue with stack frame setup
• Uses $v0 for return values and jal / jr $ra for calls and returns
• Example output:
  func_add:
      addi $sp, $sp, -32
      sw $ra, 28($sp)
      sw $fp, 24($sp)
      addi $fp, $sp, 32
      sw $a0, 0($sp)
      sw $a1, 4($sp)
      lw $t0, 0($sp)
      lw $t1, 4($sp)
      add $v0, $t0, $t1
      lw $ra, 28($sp)
      lw $fp, 24($sp)
      addi $sp, $sp, 32
      jr $ra

Example Run:
Input:
int add(int a, int b) {
    return a + b;
}

int main() {
    int x;
    x = add(5, 10);
}

Output (simplified MIPS):
add:
    lw $t0, 0($sp)
    lw $t1, 4($sp)
    add $v0, $t0, $t1
    jr $ra

main:
    li $a0, 5
    li $a1, 10
    jal add
    sw $v0, 0($sp)


# data[].attributes.body
Continued improvements to parser.y and lever.l to completey support functions. In AST.c we added 4 new node types and new func in act.h

# data[].attributes.body
·         Added updates to Parser.y

·         Added updates to Ast.h and .c

·         Added updates to Symtab.h and .c

·         Added updates to Tac.h and .c

# data[].attributes.body
Updated Symbol Table

Updated TAC

To-Do: Code Generation & Testing

# data[].attributes.headline
Christian Nshuti Manzi & Aime Serge Tuyishime

# data[].attributes.subject
Christian Nshuti Manzi & Aime Serge Tuyishime

# data[].attributes.body
1. Enhanced Symbol Table (symtable.h, symtable.c)

2. Scope Management APIs

3. Function Management APIs

4. Dead Code Elimination

- find_uncalled_functions() - Find unused functions

- remove_uncalled_functions() - Remove unused functions

- isCalled flag tracking throughout compilation

5. Enhanced Symbol Entry

- Tracks: name, type, kind, scope, initialization status

- For functions: parameter count, types, names, local scope

- For arrays: size tracking

- Automatic local scope creation for functions

# data[].attributes.body
Updated lexer and parser with added functions and work on updating other files as needed

# data[].attributes.body
Implemented full function support with scoping, parameter passing, and dead code elimination.

Updated parser, lexer, AST, symbol table, and TAC to handle function syntax and semantics.

Added APIs for scope and function management to track declarations, calls, and cleanup.

Enabled optimization by removing unused functions through an isCalled flag system.

Verified functionality with test cases demonstrating return types, local/global scopes, and void functions.

# data[].attributes.body
Adding functions:

edited lexer & parser

updated ast.h and ast.c

updating tac files

# data[].attributes.headline
Miles Bassett-Graves, Fernando Campa, and Nolan DeSchryver

# data[].attributes.subject
Miles Bassett-Graves, Fernando Campa, and Nolan DeSchryver

# data[].attributes.body
We're adding TAC optimization and adjustments to symtab so it can handle function declaration and handle scope.

# data[].attributes.body
Trying to fix errors in our parser that occurred after implementing function support last week.

# data[].attributes.body
Finished up to step 5 so far. Adding TAC generation next.

# data[].attributes.body
Debugging parser errors

# data[].attributes.body
source.cm

int add(int lhs, int rhs) {

int sum;

sum = lhs + rhs;

return sum;

}

void echoChar(char input) {

print(input);

}

void main() {

int total;

char ch;

total = add(7, 5);

print(total);

ch = echoChar('z');

}

Current Progress Implementing Lang. Support for Functions

-> Implemented function support through until codegen.c with functional MIPS code generated, but still need to implement TAC optimizations for function nodes.

-> Change CFG to allow void function calls not within an assignment statement, print statement, or expression. eg. echoFunc('c'); not c = echoFunc('c'); or print(echoFunc('c'));

# data[].attributes.body
added switch-case statements along with break and continue satements

# data[].attributes.body
Post a bulletpoint update of your compiler progress, noting the changes from Week 6

Add a screenshot

# data[].attributes.body
Added scoped symbol table (symtab.h/c): Scope, SymbolEntry, push/pop, addSymbol, lookup, offsets.

Extended AST (ast.h/c): new node kinds and constructors for functions, params, calls, arrays, return.

Updated parser (parser.y): grammar for functions, params, returns, array decl/assign, calls, complex expressions; fixed ret_type rule.

Updated lexer (scanner.l): tokens for int/float/void/return/print, brackets, numbers, identifiers.

Implemented semantic checks (ast.c): undeclared vars, type warnings, array bounds, return type checks.

Extended TAC (tac.h/c): FUNC_BEGIN/END, PARAM, CALL, RET, LABEL, array ops; TAC generation for calls/arrays.

Prepared optimizer hooks and TAC printing; added OPT_VERBOSE.

Fixed codegen (codegen.c): safe getNextTemp/lastTemp, regname helper, MIPS emission for arrays, calls, functions.

Exposed benchmarking and AST memory getters (benchmark.h/c, ast.h/c) and init functions.

Rewrote test.c to exercise arrays, functions, calls, nested expressions, and local arrays.

# data[].attributes.body
Function Implementation Progress

Added return, void, {, }, , tokens to scanner

Remaining:

- Task 2: Extend parser grammar for functions

- Task 3: Add function AST nodes

- Task 4: Implement hierarchical scope management with enterScope()/exitScope()

# data[].attributes.body
We got to step 2 and were adding the grammar to the lever and parser. We are using # to declare a function

# data[].attributes.body
Added support for functions, have yet to add scope management which I am currently working on right now along with tac generation

# data[].attributes.body
We finished step 4 of updating the Symtab files, we will pick up on step 5 next time we work

# data[].attributes.body
TO DO:

Add RETURN token for 'return' keyword

Add VOID token for 'void' keyword

Modify program rule to accept function list instead of statements

Create func_list rule for list of function declarations

Update func_list to handle single function or multiple functions

Function Call Rules

Add function call to expr rule: ID '(' arg_list ')'

Add function call variant without arguments: ID '(' ')'

Create arg_list rule for single expression

Add arg_list variant for multiple expressions with comma separatio

# data[].attributes.attachment_link.readable_text
﻿Task List for Function Implementation
* Add grammar rules in parser.y to handle function definitions, allowing for optional parameter lists.

* Ensure compatibility for both functions without parameters and those with multiple parameters.

* Extend the grammar to recognize function invocations that include argument lists.

________________


Lexer Enhancements for Function Tokens
   * Confirm that Improved_scanner.l correctly identifies and returns all tokens related to functions.

   * Lexer verification is complete — the current implementation already supports all required tokens.

________________


Symbol Table and Scope Management Plan
      * Scope Hierarchy:

         * Level 0: Represents the global scope, containing global variables and function declarations.

         * Levels 1 and higher: Represent local scopes within individual functions, including parameters and local variables.

________________


Abstract Syntax Tree (AST) for Advanced Expressions
Type Validation Approach
            * Selected strategy: Generate an error whenever incompatible data types are used together.

            * During semantic analysis, verify the types of both operands in each expression.

            * Display an error message such as:


"Error: Type mismatch in expression on line X — cannot mix int and float without an explicit cast."

# data[].attributes.body
Currently have the initial compiler steps sorted (scanner, parser, AST) to support functions.

# data[].attributes.body
We got through implementing changes through the TAC files. We were also able to test through the scanner, parser, and ast files.

# data[].attributes.body
TO DO list to implement functions:

* Add production rules in parser.y for function declarations with optional parameter lists

* Support both parameterless functions and functions with multiple parameters

* Add rules for function calls with arguments

Update Lexer for Function-Related Tokens

Ensure Improved_scanner.l properly returns all existing tokens

Status: Already complete - current lexer supports necessary tokens.

Symbol Table & Scope Management Strategy

Scope Levels:

* Level 0: Global scope (functions and global variables)

* Level 1+: Function-local scope (parameters and local variables)

AST for Complex Expressions

Type Handling Strategy:

* Option chosen: Issue error for type mismatches

* Check both operands during semantic analysis

* Error message: "Error: Type mismatch in expression on line X. Cannot mix int and float without explicit cast."

# data[].attributes.body
Currently working on implementing functions as specified in the activity. Got as far as the definitions for creating the new node types.

# data[].attributes.body
You now have a better understanding of the structure of the compiler

The attached document explains step by step, how to add support for functions.

Note the multiple places in your existing compiler you must touch, modify, and expand

The performance enhancements you worked on last week should be continuously included in this and future compiler iterations

For participation today, post an explanation of your current progress towards implementing support for functions, and a representative screenshot

# data[].attributes.attachment_link.readable_text
Function Support Roadmap 
===============================================================================

-------------------------------------------------------------------------------
Phase 1 â Grammar Rules in Bison (parser.y)
-------------------------------------------------------------------------------
Goal: Extend the language to include function definitions, parameter lists, calls, and returns.

Add token and type declarations near our existing ones:
    %token RETURN VOID
    %type <node> function func_list param_list param_decl param_list_opt
    %type <node> call arg_list arg_list_opt
    %type <node> return_stmt block

(Keep our current precedence, which already includes '+' and '-'.)

Top-level program shape to allow both declarations and functions:
    program
      : decl_list
      | func_list
      | decl_list func_list
      ;

Functions and parameters:
    func_list
      : func_list function
      | function
      ;

    function
      : type ID '(' param_list_opt ')' block
          { $$ = createFunction($1, $2, $4, $6); }
      ;

    param_list_opt
      : /* empty */ { $$ = NULL; }
      | param_list  { $$ = $1; }
      ;

    param_list
      : param_decl
      | param_list ',' param_decl
          { $$ = appendParam($1, $3); }
      ;

    param_decl
      : type ID
          { $$ = createParam($1, $2, 0); }
      | type ID '[' ']'
          { $$ = createParam($1, $2, 1); }
      ;

Blocks:
    block
      : '{' stmt_list_opt '}'
          { $$ = createBlock($2); }
      ;

Calls and returns:
    expr
      : /* existing cases */
      | ID '(' arg_list_opt ')'
          { $$ = createCall($1, $3); }
      ;

    arg_list_opt
      : /* empty */ { $$ = NULL; }
      | arg_list    { $$ = $1; }
      ;

    arg_list
      : expr
          { $$ = appendArg(NULL, $1); }
      | arg_list ',' expr
          { $$ = appendArg($1, $3); }
      ;

    stmt
      : /* existing statements */
      | return_stmt
      ;

    return_stmt
      : RETURN expr ';' { $$ = createReturn($2); }
      | RETURN ';'      { $$ = createReturn(NULL); }
      ;

-------------------------------------------------------------------------------
Phase 2 â Update the Lexer (scanner.l)
-------------------------------------------------------------------------------
Goal: Teach the scanner to recognize the new tokens used above.

Add reserved words:
    return      return RETURN;
    void        return VOID;

Add punctuation used by functions:
    "{"         return '{';
    "}"         return '}';
    ","         return ',';

Keep existing rules for identifiers, integers, strings, '+', '-', '=', '(', ')', '[', ']' as-is.

-------------------------------------------------------------------------------
Phase 3 â Symbol Table & Scope Management (semantic.c/h, symtab.c/h)
-------------------------------------------------------------------------------
Goal: Introduce function-level scope and function signatures.

1) Add a function symbol record (in symtab.h or our semantic layer):
    typedef struct {
        char* name;
        int   returnType;              // TYPE_INT / TYPE_STRING / TYPE_VOID
        int   paramCount;
        int   paramTypes[16];
        int   paramIsArray[16];
    } FunctionSymbol;

2) API (semantic.h or symtab.h):
    int  addFunctionSymbol(const char* name, int returnType,
                           const int* types, const int* isArray, int count);
    const FunctionSymbol* lookupFunctionSymbol(const char* name);

3) Scopes:
    - On entering a function (in semanticCheck for NODE_FUNC): push a new scope.
    - Insert parameters into that scope with stack offsets (like locals).
    - On exit: pop the scope.

-------------------------------------------------------------------------------
Phase 4 â AST for Complex Expressions (ast.c/h)
-------------------------------------------------------------------------------
Goal: Ensure expression AST handles nested calls naturally.

Our existing expr AST already supports binops and literals; adding call-as-expr (Phase 1) is sufficient.
No extra AST node beyond NODE_CALL is required here. (Same as above, just confirm nested parentheses and binops remain valid.)

-------------------------------------------------------------------------------
Phase 5 â AST for Function Declaration (ast.c/h)
-------------------------------------------------------------------------------
Goal: Add node types and constructors for function definitions and blocks.

In ast.h add to NodeType:
    NODE_FUNC, NODE_PARAM, NODE_PARAM_LIST, NODE_CALL, NODE_RETURN, NODE_BLOCK

Add fields in the node union:
    // function
    struct { int returnType; char* name; struct ASTNode* params; struct ASTNode* body; } func;
    // param
    struct { int type; char* name; int isArray; struct ASTNode* next; } param;
    // call
    struct { char* name; struct ASTNode* args; } call;
    // return
    struct ASTNode* retExpr;
    // block
    struct { struct ASTNode* stmts; } block;

Declare constructors:
    ASTNode* createFunction(int retType, char* name, ASTNode* params, ASTNode* body);
    ASTNode* createParam(int type, char* name, int isArray);
    ASTNode* appendParam(ASTNode* list, ASTNode* param);
    ASTNode* createCall(char* name, ASTNode* args);
    ASTNode* appendArg(ASTNode* list, ASTNode* expr);
    ASTNode* createReturn(ASTNode* optExpr);
    ASTNode* createBlock(ASTNode* stmtList);

-------------------------------------------------------------------------------
Phase 6 â AST for Return Statements (ast.c/h)
-------------------------------------------------------------------------------
Goal: Represent 'return;' and 'return expr;' clearly.

Implement:
    ASTNode* createReturn(ASTNode* optExpr) { /* set NODE_RETURN + retExpr */ }

Extend printAST to display returns:
    return <expr> or return;

(This is a focused restatement for clarity even though Phase 5 introduced NODE_RETURN.)

-------------------------------------------------------------------------------
Phase 7 â AST for Function Calls (ast.c/h)
-------------------------------------------------------------------------------
Goal: Calls as expressions (works in assignments, prints, etc.).

Implement:
    ASTNode* createCall(char* name, ASTNode* args);
    ASTNode* appendArg(ASTNode* list, ASTNode* expr);

Extend printAST to show: call name(args...).

(Same as above where calls were introduced; kept explicit for our 13-phase layout.)

-------------------------------------------------------------------------------
Phase 8 â AST for Parameter Declarations (ast.c/h)
-------------------------------------------------------------------------------
Goal: Represent parameters in the AST and normalize list handling.

Implement:
    ASTNode* createParam(int type, char* name, int isArray);
    ASTNode* appendParam(ASTNode* list, ASTNode* param);

AST print should render parameter lists and array markers (e.g., 'int x', 'int a[]').

-------------------------------------------------------------------------------
Phase 9 â AST for Array Declarations in Functions (ast.c/h, semantic.c)
-------------------------------------------------------------------------------
Goal: Confirm arrays already supported at global scope also work in function scope.

- Reuse existing NODE_ARRAY_DECL / NODE_ARRAY_ASSIGN / NODE_ARRAY_ACCESS.
- Ensure in semantic check that array decls inside functions are added to the function scope (not global).
- Same as above: functionality exists; this phase adapts it for function-local behavior.

-------------------------------------------------------------------------------
Phase 10 â Semantic Checks for Functions (semantic.c/h)
-------------------------------------------------------------------------------
Goal: Enforce arity, argument types, and return types.

Checks to add:
1) On NODE_FUNC:
   - Register function symbol (name, returnType, params).
   - Create a function-scope; insert parameters with offsets.
2) On NODE_CALL:
   - Lookup function by name.
   - Verify arg count == paramCount.
   - For each argument, ensure exprType(arg) matches paramTypes[i].
3) On NODE_RETURN:
   - If return has expr: exprType must match current function's returnType.
   - If 'return;' ensure current function return type is TYPE_VOID.

(This extends our current exprType/type rules without altering existing behavior.)

-------------------------------------------------------------------------------
Phase 11 â Generate TAC (tac.h/tac.c)
-------------------------------------------------------------------------------
Goal: Add interprocedural TAC ops and integrate with our current TAC list/printing.

1) Extend TACOp in tac.h:
    TAC_FUNC_BEGIN, TAC_FUNC_END, TAC_PARAM, TAC_ARG, TAC_CALL, TAC_RET

2) Emit TAC for functions:
   - On function begin: append TAC_FUNC_BEGIN with result=functionName.
   - For each parameter (optional): append TAC_PARAM paramName.
   - Body TAC is generated as usual.
   - Ensure a final TAC_RET for void functions if none present.
   - Append TAC_FUNC_END at the end.

3) Emit TAC for returns:
   - 'return x;' â evaluate x into t, append TAC_RET t.
   - 'return;'   â append TAC_RET (no arg).

4) Emit TAC for calls:
   - For each argument in order: evaluate to temp and append TAC_ARG temp.
   - Append TAC_CALL with arg1=functionName, arg2=numberOfArgs (as string), result=destTemp (or NULL for void).

5) Update printTAC/printOptimizedTAC:
   - func name begin/end, arg, call, ret formatting consistent with our style.

-------------------------------------------------------------------------------
Phase 12 â Optimizer (tac.c or optimizer.c)
-------------------------------------------------------------------------------
Goal: Keep optimizations safe in presence of calls and returns.

- Constant folding/propagation: safe within a basic block; stop at CALL boundaries.
- Dead code elimination: do not remove ARG/CALL/RET.
- Print an "Optimized TAC" section as you already do (extend printer to handle new ops).
- Same as above, but now aware of function-related TAC.

-------------------------------------------------------------------------------
Phase 13 â Code Generation (codegen.c)
-------------------------------------------------------------------------------
Goal: Lower function TAC to MIPS using our current stack/offset model.

Recommended mapping:
1) TAC_FUNC_BEGIN name
   - Emit label 'name:'
   - Prologue: addi $sp, $sp, -frameSize; sw $ra, frame-4($sp); save callee-saved as needed.
   - Establish frame offsets for parameters and locals (reuse our getVarOffset model, but per function).

2) TAC_ARG (caller side)
   - Move arg temps into $a0â$a3 in order; if >4, spill to stack per our chosen ABI.

3) TAC_CALL name, nArgs, result
   - jal name
   - If 'result' exists: move $v0 into its temp/stack slot.

4) TAC_RET x / TAC_RET
   - If x: move to $v0
   - Epilogue: restore $ra, addi $sp, $sp, +frameSize; jr $ra

5) TAC_FUNC_END
   - (May be a no-op if epilogue emitted by RET; otherwise provide a label-based epilogue.)

Integrate with our existing string printing and concat helper. Our current code already distinguishes string vs int via exprType in codegen; reuse that for return values and call results.

-------------------------------------------------------------------------------
Implementation Order (Quick Checklist)
-------------------------------------------------------------------------------
- Phase 2 (lexer) and Phase 1 (parser) in tandem.
- Phase 5â8 (AST nodes/constructors/printer).
- Phase 3 & 10 (symbol table + semantic checks).
- Phase 11 (TAC ops + generation + printers).
- Phase 13 (MIPS codegen for funcs).
- Phase 12 (optimizer adjustments).

-------------------------------------------------------------------------------
End of 13-Phase Roadmap
-------------------------------------------------------------------------------

# data[].attributes.body
Since our grammar already has sections for declaring and assigning, I would assume we could just put our function case handling into those sections like we would anything else. We would need to make some function expressions though.

Lexer already updated with tokens like () and {}

I think we could have a single function for creating a function like createFunction() that would probably need to pass in some kind of linked list in order to handle dynamic parameters picked by the user. On top of that, there will be fixed parameters like name and return type. I think making a fixed return type would simplify things for use so we can just check each return statement and compare it to the return type instead of comparing all the return statements to eachother to determine if they match.

We will need to set up floats probably and set up error handling

I think the more specific we get with each step the better the AST will be. In theory we could have something simple like > declareFunction or we could get super technical in order to understand what is really going on behind the scenes.

Same as above

Same as above

Same as above

Same as above

Handling the scope is going to be tricky, not yet sure how to handle the idea of a local vs global variable. Maybe we would need to make a synthetic symbol table for each function that gets put in the main symbol table? I also don't think we need to worry about void for now, we can just say it needs to return some value even if it isn't used. In the TAC, we could just throw that value away if the user doesnt assign it to a variable, if I am understanding TAC correctly.

TAC is something I am still trying to understand implementation wise. I understand the core concepts of how it works, but I think this will be the most difficult section. There are going to be a lot of values in a function, especially because they will be dynamic in length because they are defined by the user, so the TAC will probably be the most complex section.

The above statement goes for the optimizer was well.

Code generation should not be too difficult once we get the flow above. We should have a full map of how the function declaration works and be able to implement is into the code generation.

# data[].attributes.attachment_link.readable_text
Function Implementation Plan for Mini Compiler
Minimal Test Program
cint add(int a, int b) {
    int result;
    result = a + b;
    return result;
}

int main() {
    int x;
    int y;
    int sum;
    
    x = 10;
    y = 20;
    sum = add(x, y);
    print(sum);
    
    return 0;
}

1. Grammar Rules in Bison
Function Declaration (with parameters):
yaccfunction_decl: type ID '(' param_list ')' '{' stmt_list '}'
             | type ID '(' ')' '{' stmt_list '}'
Function Call (with parameters):
yaccexpr: ID '(' arg_list ')'
    | ID '(' ')'
Return Statement:
yaccstmt: RETURN expr ';'
    | RETURN ';'
Parameter List:
yaccparam_list: param
          | param_list ',' param
          
param: type ID

2. Lexer Token Updates
New Keywords:

RETURN - for return statements
VOID - for void functions (optional)

Existing Tokens (already have):

INT - for return types and parameter types
ID - for function names and parameter names
Parentheses, braces, comma (already supported)


3. Symbol Table & Scope Management
Strategy: Nested Scope with Stack-Based Management
Function Scope Entry Structure:
ctypedef struct FunctionSymbol {
    char* name;              // Function name
    VarType returnType;      // INT, VOID, etc.
    int paramCount;          // Number of parameters
    Parameter params[10];    // Parameter list
    int defined;             // Flag: declared vs defined
} FunctionSymbol;
Scope Management:

Global Scope: Functions and global variables
Function Scope: Parameters and local variables
Use scope stack: push on function entry, pop on function exit
Search order: Local â Global

Symbol Table Additions:
ctypedef struct {
    // Existing variable table
    Symbol vars[MAX_VARS];
    int varCount;
    
    // New function table
    FunctionSymbol functions[MAX_FUNCS];
    int funcCount;
    
    // Scope tracking
    int currentScope;        // 0 = global, 1+ = function
    int scopeOffsets[10];    // Stack offsets per scope
} SymbolTable;

4. AST for Complex Expressions
Already Supported:

Binary operators (+, -, *)
Parentheses (handled by parser precedence)
Variables and constants

Division Handling Strategy:

Option 1 (Simple): Integer division only, no type coercion
Option 2 (Advanced): Add float type, require explicit casting

Recommendation: Stick with integer-only for now, add explicit cast operator later
Example: (2 + x) * (y - 12) / (z + 100)

Parser already handles this with precedence rules
AST builds nested BINOP nodes automatically


5. AST for Function Declaration
New AST Node Type:
ctypedef enum {
    // ... existing nodes ...
    NODE_FUNC_DECL,
    NODE_PARAM_LIST,
    NODE_RETURN
} NodeType;

// In ASTNode union:
struct {
    char* name;
    VarType returnType;
    struct ASTNode* params;     // Parameter list
    struct ASTNode* body;       // Statement list
} func_decl;
Creation Function:
cASTNode* createFuncDecl(char* name, VarType type, 
                        ASTNode* params, ASTNode* body);

6. AST for Return Statement
Structure:
cstruct {
    struct ASTNode* expr;    // NULL for void return
} return_stmt;
Creation Function:
cASTNode* createReturn(ASTNode* expr);

7. AST for Function Call
New Node Type:
cNODE_FUNC_CALL

struct {
    char* name;              // Function name
    struct ASTNode* args;    // Argument list
} func_call;
Creation Function:
cASTNode* createFuncCall(char* name, ASTNode* args);

8. AST for Parameter Declaration
Structure:
cNODE_PARAM

struct {
    char* name;
    VarType type;
    struct ASTNode* next;    // Linked list
} param;

9. AST for Array Declaration
Already Implemented - just extend to support in function scope

10. Semantic Checks
A. Variable Scope Checking:

When encountering a variable, search current scope first, then global
Error if not found in either scope

B. Type Compatibility:

For now: All operations are integer-only
Check: int + int = int (valid), no mixing types

C. Array Bounds:

Static bounds (compile-time): Check if arr[5] when size is 3
Dynamic bounds (runtime): Skip for now (requires runtime checks)

D. Function Parameters:

Count arguments vs parameters
Check each argument type matches parameter type

E. Return Type Matching:

Track expected return type from function declaration
Verify return statement expression type matches

F. Void Functions:

Allow return; with no expression
Disallow return x; with expression

G. Return Expression Types (Support):

return x; â
return 5; â
return a + b; â
return myFunc(x,y,z); â (if team size > 2)
return void; â (error)

H. Typecasting:

Not supported initially
Add explicit cast operator (int) later if needed

I. Type Coercion:

Not supported - strict type checking only


11. TAC Generation for Functions
Function Label:
LABEL _functionName:
    DECL param1
    DECL param2
    DECL localVar1
    ... function body TAC ...
    RETURN result
Function Call:
PARAM arg1          // Push arguments
PARAM arg2
CALL _functionName  // Jump to function
t0 = RETVAL        // Get return value
MIPS Register Conventions:

$a0-$a3: First 4 arguments
$v0: Return value
$ra: Return address
Stack: Additional parameters

Return Statement:
TAC: RETURN expr
Generated:
    result = expr evaluation
    MOVE $v0, result
    RETURN

12. Optimizer Extensions
Already Have:

Constant folding â
Constant propagation â

Add:
Dead Code Elimination:

Detect unreachable code after return
Remove unused variables

Example:
Before:
    x = 5
    return x
    y = 10        // Dead code

After:
    x = 5
    return x
Function Inlining (Advanced):

Replace simple function calls with inline code
Only for small functions with no recursion


13. Code Generation
Function Prologue (Entry):
mips_functionName:
    # Save return address
    addi $sp, $sp, -4
    sw $ra, 0($sp)
    
    # Allocate local variables
    addi $sp, $sp, -N
    
    # Save arguments from registers to stack
    sw $a0, offset($sp)
    sw $a1, offset+4($sp)
Function Epilogue (Exit):
mips    # Load return value into $v0
    lw $v0, result_offset($sp)
    
    # Deallocate locals
    addi $sp, $sp, N
    
    # Restore return address
    lw $ra, 0($sp)
    addi $sp, $sp, 4
    
    # Return to caller
    jr $ra
Function Call:
mips    # Load arguments into registers
    lw $a0, x_offset($sp)
    lw $a1, y_offset($sp)
    
    # Call function
    jal _functionName
    
    # Get return value
    move $t0, $v0
    sw $t0, sum_offset($sp)

Execution Flow Example
Source:
cint add(int a, int b) {
    return a + b;
}
int main() {
    int x = 10;
    int sum = add(x, 20);
    print(sum);
}
TAC:
LABEL _add:
    DECL a
    DECL b
    t0 = a + b
    RETURN t0

LABEL _main:
    DECL x
    DECL sum
    x = 10
    PARAM x
    PARAM 20
    t1 = CALL _add
    sum = t1
    PRINT sum
MIPS:
mips_add:
    sw $ra, -4($sp)
    addi $sp, $sp, -8
    sw $a0, 0($sp)
    sw $a1, 4($sp)
    lw $t0, 0($sp)
    lw $t1, 4($sp)
    add $v0, $t0, $t1
    addi $sp, $sp, 8
    lw $ra, 0($sp)
    jr $ra

_main:
    addi $sp, $sp, -8
    li $t0, 10
    sw $t0, 0($sp)
    lw $a0, 0($sp)
    li $a1, 20
    jal _add
    sw $v0, 4($sp)
    lw $a0, 4($sp)
    li $v0, 1
    syscall

# data[].attributes.body
Plan for Adding Functions to Language & Compiler:

Determine grammar (Optional main(), Free-Standing Statements, Decl+Assign)

Determine scope management strategy

Designate tasks for development

Update Files in Order (Finalize Grammar Choices Towards End)

# data[].attributes.attachment_link.readable_text
﻿________________


1. Minimal C-minus Program with Functions
int add(int a, int b) {
    return a + b;
}


int main() {
    int x = 5;
    int y = 10;
    int result = add(x, y);
    print(result);
    return 0;
}


________________


2. Implementation Plan for Each Point
Point 1: Grammar Rules in Bison (with and without parameters)
Strategy:
* Add production rules in parser.y for function declarations with optional parameter lists
* Support both parameterless functions and functions with multiple parameters
* Add rules for function calls with arguments
Grammar additions:
program:
    function_list
    ;


function_list:
    function
    | function_list function
    ;


function:
    TYPE ID '(' param_list ')' block
    | TYPE ID '(' ')' block              /* no parameters */
    ;


param_list:
    TYPE ID
    | param_list ',' TYPE ID
    ;


call_expr:
    ID '(' ')'                           /* no arguments */
    | ID '(' arg_list ')'
    ;


arg_list:
    expr
    | arg_list ',' expr
    ;


________________


Point 2: Update Lexer for Function-Related Tokens
Strategy:
* The lexer already handles most tokens (TYPE, ID, parentheses, commas)
* No major changes needed since keywords are already tokenized
* Ensure Improved_scanner.l properly returns all existing tokens
Status: Already complete - current lexer supports necessary tokens.
________________
Point 3: Symbol Table & Scope Management Strategy
Current Issue: symtab.h only tracks flat variable names without scope information. Proposed Strategy: Scope Levels:
* Level 0: Global scope (functions and global variables)
* Level 1+: Function-local scope (parameters and local variables)
Enhanced Symbol Table Structure:
typedef struct SymbolNode {
    char* name;
    int offset;
    int isArray;
    int arraySize;
    int scopeLevel;              /* NEW: 0=global, 1+=local */
    char* funcContext;           /* NEW: which function (NULL if global) */
    
    /* For functions */
    int isFunction;              /* NEW: 1 if this is a function */
    char* returnType;            /* NEW: return type (e.g., "int") */
    int paramCount;              /* NEW: number of parameters */
    struct ParamInfo* params;    /* NEW: parameter list */
    
    struct SymbolNode* next;
} SymbolNode;


typedef struct ParamInfo {
    char* name;
    char* type;
    int offset;                  /* offset within function frame */
} ParamInfo;


Scope Management:
* Maintain a global currentScope and currentFunction string
* When entering a function, push scope and set current function name
* When exiting, pop scope and restore previous context
* Lookups search current scope first, then fall back to global scope
________________


Point 4: AST for Complex Expressions
Current Status: Already implemented in ast.h:14 and codegen.c:57-127. Type Handling Strategy:
* Option chosen: Issue error for type mismatches
* Check both operands during semantic analysis
* Error message: "Error: Type mismatch in expression on line X. Cannot mix int and float without explicit cast."
For expressions like: Result = (2 + x)*(y - 12.00001)/(z + m + 100)
* The existing AST handles nested NODE_BINOP nodes correctly
* Add semantic check during TAC generation to verify all operands are compatible types
________________


Point 5: AST for Function Declaration
New AST Node:
typedef enum {
    // ... existing types ...
    NODE_FUNC_DECL,       /* Function declaration */
    NODE_PARAM_DECL,      /* Parameter declaration */
    NODE_FUNC_CALL,       /* Function call */
} NodeType;


/* In ASTNode union: */
struct {
    char* returnType;          /* "int", "void", etc. */
    char* name;                /* function name */
    struct ASTNode* params;    /* linked list of parameters */
    struct ASTNode* body;      /* function body (statement list) */
} func_decl;


Constructor:
ASTNode* createFuncDecl(char* returnType, char* name, 
                       ASTNode* params, ASTNode* body);


________________


Point 6: AST for Return Statement
Current Status: Already implemented in ast.h:25 and codegen.c:277-280. Enhancement Needed:
* Currently just moves value to $v0
* Need to add proper function epilogue (restore stack, jump to caller)
________________


Point 7: AST for Function Call
New AST Node:
struct {
    char* funcName;            /* name of function to call */
    struct ASTNode* args;      /* expression list of arguments */
} func_call;


Constructor:
ASTNode* createFuncCall(char* funcName, ASTNode* args);


________________


Point 8: AST for Parameter Declaration
Strategy: Reuse existing NODE_DECL but add context flag. Alternative: Create dedicated NODE_PARAM_DECL:
struct {
    char* type;                /* "int", etc. */
    char* name;                /* parameter name */
    struct ASTNode* next;      /* next parameter in list */
} param_decl;


________________


Point 9: AST for Array Declaration
Current Status: Already implemented in ast.h:26 and ast.c. Enhancement Needed:
* Complete the code generation in codegen.c (currently missing NODE_ARRAY_DECL case)
* Implement bounds checking during semantic analysis
________________


Point 10: Semantic Checks
Check 1: Variable Scope Validation
During TAC generation in tac.c:generateTACExpr, before calling getVarOffset:
if (!isVarInScope(varName, currentFunction)) {
    fprintf(stderr, "Error: Variable '%s' not declared in current scope\n", varName);
    exit(1);
}
* Check 2: Type Compatibility
* Add new function checkTypeCompatibility(ASTNode* left, ASTNode* right) called from binary operations
* Look up types in symbol table and verify they match
Check 3: Array Bounds Checking
During constant folding, if index is a constant:
if (index < 0 || index >= arraySize) {
    fprintf(stderr, "Error: Array index %d out of bounds [0..%d]\n", 
            index, arraySize-1);
}
* * For runtime indices, generate MIPS bounds check code
Check 4: Function Parameter Validation
* When generating TAC for function call, count arguments
Look up function in symbol table and verify:
if (argCount != funcNode->paramCount) {
    fprintf(stderr, "Error: Function '%s' expects %d arguments, got %d\n",
            funcName, funcNode->paramCount, argCount);
}
* * Check each argument type matches parameter type
Check 5: Return Type Matching
During NODE_RETURN processing in codegen.c:277:
char* returnType = inferExprType(node->data.ret_expr);
if (strcmp(returnType, currentFunction->returnType) != 0) {
    fprintf(stderr, "Error: Return type mismatch in function '%s'\n",
            currentFunction->name);
}
* Check 6: Void Function Returns
* If function return type is "void":
   * Allow return; (no expression)
   * Error on return expr;
________________


Point 11: Return Statement Flexibility
Support for:
* ✅ return x - Already works via codegen.c:277-280
* ✅ return 5 - Works through NODE_NUM in expression
* ✅ return a + b - Works through NODE_BINOP evaluation
* ✅ return myFunc(x,y,z) - Will work once function calls generate result in register
* ❌ return void - Not allowed (semantic error)
Implementation: All cases use the same code path: evaluate expression → move to $v0 → return.
________________
Point 12: Typecasting & Type Coercion
Decision: Strict typing with explicit errors (no implicit coercion) Rationale:
* Educational compiler - explicit is better for learning
* Simpler implementation
* Students understand type system better
If needed later: Add cast syntax like (float)x with new NODE_CAST AST node.
________________
Point 13: TAC Generation for Functions
TAC Instructions to Add:
typedef enum {
    // ... existing ops ...
    TAC_FUNC_BEGIN,    /* Mark function start */
    TAC_FUNC_END,      /* Mark function end */
    TAC_PARAM,         /* Declare parameter */
    TAC_CALL,          /* Function call */
    TAC_RETURN,        /* Return statement */
    TAC_ARG,           /* Pass argument to call */
} TACOp;


Example TAC for:
int add(int a, int b) { return a + b; }
int x = add(5, 10);


Generated TAC:
FUNC_BEGIN add
PARAM a
PARAM b
t0 = a + b
RETURN t0
FUNC_END add


FUNC_BEGIN main
DECL x
ARG 5
ARG 10
x = CALL add, 2
FUNC_END main


Register Management:
* MIPS Convention: Use $a0-$a3 for first 4 arguments
* Additional args: Pass via stack
* Return value: Always in $v0
GOTO Management:
* Generate labels: func_add:, func_main:
* For calls: jal func_add
* For returns: jr $ra
________________


Point 14-15: Optimizer Enhancements
Already Implemented in tac.c:209-328:
*  Constant folding
*  Copy propagation
To Add: Dead Code Elimination:
* Track which variables are used
* Remove assignments to unused temps
* Example: If t5 = x + y but t5 never used, delete instruction
Function-Specific Optimizations:
* Inline simple functions (single expression)
* Tail call optimization
* Remove redundant parameter copies
________________


Point 16: Code Generation (MIPS)
Function Prologue (generated by genStmt for NODE_FUNC_DECL):
func_add:
    # Save caller's frame
    addi $sp, $sp, -32        # Allocate frame
    sw $ra, 28($sp)           # Save return address
    sw $fp, 24($sp)           # Save frame pointer
    addi $fp, $sp, 32         # Set new frame pointer
    
    # Copy parameters from $a registers to stack
    sw $a0, 0($sp)            # param a at offset 0
    sw $a1, 4($sp)            # param b at offset 4


Function Epilogue (at NODE_RETURN):
   # Return value already in $v0
    lw $ra, 28($sp)           # Restore return address
    lw $fp, 24($sp)           # Restore frame pointer
    addi $sp, $sp, 32         # Deallocate frame
    jr $ra                    # Return to caller


Function Call (at NODE_FUNC_CALL):
   # Evaluate and move arguments to $a0-$a3
    li $a0, 5                 # First argument
    li $a1, 10                # Second argument
    jal func_add              # Call function
    # Result now in $v0
    sw $v0, offset($sp)       # Store result


________________


Summary: Execution Flow
1. Lexer tokenizes function syntax → tokens flow to parser
2. Parser builds AST with NODE_FUNC_DECL, NODE_FUNC_CALL, NODE_RETURN nodes
3. Symbol Table populated during first AST traversal (function names, parameters, locals tracked with scope)
4. Semantic Analysis validates scopes, types, parameter counts, return types
5. TAC Generation produces intermediate code with function labels, parameter passing, calls
6. Optimizer performs constant folding, propagation, dead code elimination on TAC
7. Code Generation emits MIPS assembly with proper calling conventions, stack management, register usage
8. Result: Working compiler that supports modular functions with parameters and return values
9.

# data[].attributes.attachment_link.readable_text
﻿________________


1. Minimal C-minus Program with Functions
int add(int a, int b) {
    return a + b;
}


int main() {
    int x = 5;
    int y = 10;
    int result = add(x, y);
    print(result);
    return 0;
}


________________


2. Implementation Plan for Each Point
Point 1: Grammar Rules in Bison (with and without parameters)
Strategy:
* Add production rules in parser.y for function declarations with optional parameter lists
* Support both parameterless functions and functions with multiple parameters
* Add rules for function calls with arguments
Grammar additions:
program:
    function_list
    ;


function_list:
    function
    | function_list function
    ;


function:
    TYPE ID '(' param_list ')' block
    | TYPE ID '(' ')' block              /* no parameters */
    ;


param_list:
    TYPE ID
    | param_list ',' TYPE ID
    ;


call_expr:
    ID '(' ')'                           /* no arguments */
    | ID '(' arg_list ')'
    ;


arg_list:
    expr
    | arg_list ',' expr
    ;


________________


Point 2: Update Lexer for Function-Related Tokens
Strategy:
* The lexer already handles most tokens (TYPE, ID, parentheses, commas)
* No major changes needed since keywords are already tokenized
* Ensure Improved_scanner.l properly returns all existing tokens
Status: Already complete - current lexer supports necessary tokens.
________________
Point 3: Symbol Table & Scope Management Strategy
Current Issue: symtab.h only tracks flat variable names without scope information. Proposed Strategy: Scope Levels:
* Level 0: Global scope (functions and global variables)
* Level 1+: Function-local scope (parameters and local variables)
Enhanced Symbol Table Structure:
typedef struct SymbolNode {
    char* name;
    int offset;
    int isArray;
    int arraySize;
    int scopeLevel;              /* NEW: 0=global, 1+=local */
    char* funcContext;           /* NEW: which function (NULL if global) */
    
    /* For functions */
    int isFunction;              /* NEW: 1 if this is a function */
    char* returnType;            /* NEW: return type (e.g., "int") */
    int paramCount;              /* NEW: number of parameters */
    struct ParamInfo* params;    /* NEW: parameter list */
    
    struct SymbolNode* next;
} SymbolNode;


typedef struct ParamInfo {
    char* name;
    char* type;
    int offset;                  /* offset within function frame */
} ParamInfo;


Scope Management:
* Maintain a global currentScope and currentFunction string
* When entering a function, push scope and set current function name
* When exiting, pop scope and restore previous context
* Lookups search current scope first, then fall back to global scope
________________


Point 4: AST for Complex Expressions
Current Status: Already implemented in ast.h:14 and codegen.c:57-127. Type Handling Strategy:
* Option chosen: Issue error for type mismatches
* Check both operands during semantic analysis
* Error message: "Error: Type mismatch in expression on line X. Cannot mix int and float without explicit cast."
For expressions like: Result = (2 + x)*(y - 12.00001)/(z + m + 100)
* The existing AST handles nested NODE_BINOP nodes correctly
* Add semantic check during TAC generation to verify all operands are compatible types
________________


Point 5: AST for Function Declaration
New AST Node:
typedef enum {
    // ... existing types ...
    NODE_FUNC_DECL,       /* Function declaration */
    NODE_PARAM_DECL,      /* Parameter declaration */
    NODE_FUNC_CALL,       /* Function call */
} NodeType;


/* In ASTNode union: */
struct {
    char* returnType;          /* "int", "void", etc. */
    char* name;                /* function name */
    struct ASTNode* params;    /* linked list of parameters */
    struct ASTNode* body;      /* function body (statement list) */
} func_decl;


Constructor:
ASTNode* createFuncDecl(char* returnType, char* name, 
                       ASTNode* params, ASTNode* body);


________________


Point 6: AST for Return Statement
Current Status: Already implemented in ast.h:25 and codegen.c:277-280. Enhancement Needed:
* Currently just moves value to $v0
* Need to add proper function epilogue (restore stack, jump to caller)
________________


Point 7: AST for Function Call
New AST Node:
struct {
    char* funcName;            /* name of function to call */
    struct ASTNode* args;      /* expression list of arguments */
} func_call;


Constructor:
ASTNode* createFuncCall(char* funcName, ASTNode* args);


________________


Point 8: AST for Parameter Declaration
Strategy: Reuse existing NODE_DECL but add context flag. Alternative: Create dedicated NODE_PARAM_DECL:
struct {
    char* type;                /* "int", etc. */
    char* name;                /* parameter name */
    struct ASTNode* next;      /* next parameter in list */
} param_decl;


________________


Point 9: AST for Array Declaration
Current Status: Already implemented in ast.h:26 and ast.c. Enhancement Needed:
* Complete the code generation in codegen.c (currently missing NODE_ARRAY_DECL case)
* Implement bounds checking during semantic analysis
________________


Point 10: Semantic Checks
Check 1: Variable Scope Validation
During TAC generation in tac.c:generateTACExpr, before calling getVarOffset:
if (!isVarInScope(varName, currentFunction)) {
    fprintf(stderr, "Error: Variable '%s' not declared in current scope\n", varName);
    exit(1);
}
* Check 2: Type Compatibility
* Add new function checkTypeCompatibility(ASTNode* left, ASTNode* right) called from binary operations
* Look up types in symbol table and verify they match
Check 3: Array Bounds Checking
During constant folding, if index is a constant:
if (index < 0 || index >= arraySize) {
    fprintf(stderr, "Error: Array index %d out of bounds [0..%d]\n", 
            index, arraySize-1);
}
* * For runtime indices, generate MIPS bounds check code
Check 4: Function Parameter Validation
* When generating TAC for function call, count arguments
Look up function in symbol table and verify:
if (argCount != funcNode->paramCount) {
    fprintf(stderr, "Error: Function '%s' expects %d arguments, got %d\n",
            funcName, funcNode->paramCount, argCount);
}
* * Check each argument type matches parameter type
Check 5: Return Type Matching
During NODE_RETURN processing in codegen.c:277:
char* returnType = inferExprType(node->data.ret_expr);
if (strcmp(returnType, currentFunction->returnType) != 0) {
    fprintf(stderr, "Error: Return type mismatch in function '%s'\n",
            currentFunction->name);
}
* Check 6: Void Function Returns
* If function return type is "void":
   * Allow return; (no expression)
   * Error on return expr;
________________


Point 11: Return Statement Flexibility
Support for:
* ✅ return x - Already works via codegen.c:277-280
* ✅ return 5 - Works through NODE_NUM in expression
* ✅ return a + b - Works through NODE_BINOP evaluation
* ✅ return myFunc(x,y,z) - Will work once function calls generate result in register
* ❌ return void - Not allowed (semantic error)
Implementation: All cases use the same code path: evaluate expression → move to $v0 → return.
________________
Point 12: Typecasting & Type Coercion
Decision: Strict typing with explicit errors (no implicit coercion) Rationale:
* Educational compiler - explicit is better for learning
* Simpler implementation
* Students understand type system better
If needed later: Add cast syntax like (float)x with new NODE_CAST AST node.
________________
Point 13: TAC Generation for Functions
TAC Instructions to Add:
typedef enum {
    // ... existing ops ...
    TAC_FUNC_BEGIN,    /* Mark function start */
    TAC_FUNC_END,      /* Mark function end */
    TAC_PARAM,         /* Declare parameter */
    TAC_CALL,          /* Function call */
    TAC_RETURN,        /* Return statement */
    TAC_ARG,           /* Pass argument to call */
} TACOp;


Example TAC for:
int add(int a, int b) { return a + b; }
int x = add(5, 10);


Generated TAC:
FUNC_BEGIN add
PARAM a
PARAM b
t0 = a + b
RETURN t0
FUNC_END add


FUNC_BEGIN main
DECL x
ARG 5
ARG 10
x = CALL add, 2
FUNC_END main


Register Management:
* MIPS Convention: Use $a0-$a3 for first 4 arguments
* Additional args: Pass via stack
* Return value: Always in $v0
GOTO Management:
* Generate labels: func_add:, func_main:
* For calls: jal func_add
* For returns: jr $ra
________________


Point 14-15: Optimizer Enhancements
Already Implemented in tac.c:209-328:
*  Constant folding
*  Copy propagation
To Add: Dead Code Elimination:
* Track which variables are used
* Remove assignments to unused temps
* Example: If t5 = x + y but t5 never used, delete instruction
Function-Specific Optimizations:
* Inline simple functions (single expression)
* Tail call optimization
* Remove redundant parameter copies
________________


Point 16: Code Generation (MIPS)
Function Prologue (generated by genStmt for NODE_FUNC_DECL):
func_add:
    # Save caller's frame
    addi $sp, $sp, -32        # Allocate frame
    sw $ra, 28($sp)           # Save return address
    sw $fp, 24($sp)           # Save frame pointer
    addi $fp, $sp, 32         # Set new frame pointer
    
    # Copy parameters from $a registers to stack
    sw $a0, 0($sp)            # param a at offset 0
    sw $a1, 4($sp)            # param b at offset 4


Function Epilogue (at NODE_RETURN):
   # Return value already in $v0
    lw $ra, 28($sp)           # Restore return address
    lw $fp, 24($sp)           # Restore frame pointer
    addi $sp, $sp, 32         # Deallocate frame
    jr $ra                    # Return to caller


Function Call (at NODE_FUNC_CALL):
   # Evaluate and move arguments to $a0-$a3
    li $a0, 5                 # First argument
    li $a1, 10                # Second argument
    jal func_add              # Call function
    # Result now in $v0
    sw $v0, offset($sp)       # Store result


________________


Summary: Execution Flow
1. Lexer tokenizes function syntax → tokens flow to parser
2. Parser builds AST with NODE_FUNC_DECL, NODE_FUNC_CALL, NODE_RETURN nodes
3. Symbol Table populated during first AST traversal (function names, parameters, locals tracked with scope)
4. Semantic Analysis validates scopes, types, parameter counts, return types
5. TAC Generation produces intermediate code with function labels, parameter passing, calls
6. Optimizer performs constant folding, propagation, dead code elimination on TAC
7. Code Generation emits MIPS assembly with proper calling conventions, stack management, register usage
8. Result: Working compiler that supports modular functions with parameters and return values
9.

# data[].attributes.body
In your groups read the to-do list below, and post your plan for adding functions to your language and compiler:

To Do List:

Enter all grammar rules in Bison - with and without parameters

Update the Lexer to return all relevant tokens

Update symbol table and decide on a scope management strategy

Function name, return type, and scope

Parameter name, types, and scope

Local variables, types, and scope

Create AST for complex expressions, which include multiple operators and parentheses

e.g., Res = x/y
Options:

Coerce each variable to be float, regardless of initial declaration, by updating the appropriate symbol table:
In C or Java: (float) Res = (float)x / (float)y  OR

Issue an error: “Error: Type mismatch. I suggest you typecast all variables on line ## to float”

Result = (2 + x)*(y - 12.00001)/(z + m + 100)

Create AST for function declaration

AST for return statement (add to the section that handles statements)

Create AST for function call

Create AST for parameter declaration

Create AST for array declaration

Semantic checks:

Are variables used inside the function declared in the expected scope (i.e. local or global)?

Are all types of variables in an expression compatible?

Is the current array index within the defined boundaries?

Check types and number of function parameters

Does the returned type match the declared type?

If you allow void function type, then return is an error (unless you decide on return null)

Do you allow?:

return x  (required)

return 5  (required)

return a + b (required for teams > 2)

return myFunc(x,y,z)

return void

Typecasting - decide if/how to handle

Type coercion - decide if/how to handle

Generate TAC - be mindful of:

Labels for beginning of functions

Registers for passing function parameters

Registers for returning function values

Manage GOTO statements - add to TAC in appropriate positions

Optimizer:

Constant folding

Constant propagation

Dead code elimination

Generate Optimized TAC

Code generation

DELIVERABLE

Post the minimal program in your version C-minus, which implements functions

Illustrate your implementation of the above 13 points by showing how do you envision your code to be written and executed