svhawkins / B-Minor-Compiler

COMP 4060 B-Minor Compiler
2 stars 0 forks source link

COMP 4060 201 Assignment 4: Typechecker (UPDATED) 05.04.2023


Updates:

  1. Added unit tests for (now) all error messages
  2. Added error messages for function prototype/definiton redefinitons
  3. Added typechecking for array types (their size fields) (with associated error messages)
  4. Argument lists are now printed
  5. Declaration lists of function declarations containing prototype and definition no longer cause segmentation faults

Files 6 directories, 101 files Not all files are shown. Test, old, or .bminor files are not shown in this file tree.

. ├── Makefile ├── README.txt ├── source │   ├── decl.c │   ├── decl.h │   ├── expr.c │   ├── expr.h │   ├── grammar.bison │   ├── hash_table.c │   ├── hash_table.h │   ├── main.c │   ├── param_list.c │   ├── param_list.h │   ├── parse.c │   ├── parser.c │   ├── parser.h │   ├── print.c │   ├── scanner.c │   ├── scanner.flex │   ├── stack.c : implementation file for a 'generic' stack interface │   ├── stack.h : header file for a 'generic' stack interface │   ├── stmt.c │   ├── stmt.h │   ├── symbol.c │   ├── symbol.h │   ├── symbol_table.c : implementation file for symbol table interface │   ├── symbol_table.h : header file for symbol table interface, using a 'generic' stack │   ├── type.c │   └── type.h ├── test ├── tests │   ├── ast : directory for ast tests + code │   ├── parser : directory for parser tests + code │   ├── scanner : directory for scanner tests + code │   ├── symbol_table │   │   ├── test_stack.c : symbol table + name resolution tests │   │   └── test_typecheck.c : typechecking tests │   ├── test.c : runs all test executables │   ├── test_ast │   ├── test_factory │   ├── test_parse │   ├── test_print │   ├── test_scan │   ├── test_stack : runs name resolution + symbol table tests (includes structures that compose them) │   └── test_typecheck : runs typechecking tests └── typecheck


EXECUTABLES commands: [all] - compiles all code targets under [compiler] and [tests] [compiler] - compiles all source code targets: [scan], [parse], [print], [typecheck] [tests] - compiles all test code targets: scanner: [tests/test_scan] parser: [tests/test_parse] ast: [tests/test_factory], [tests/test_print], [tests/test_ast] typechecking: [tests/test_stack], [tests/test_typecheck]

The new executable is [typecheck]

[typecheck]: compiled by [make], [make all], [make compiler], or [make typecheck] [typecheck] runs a typechecker, for either programs or test programs and prints out the resulting symbol table as well as any errors that occur when doing name resolution or typechecking. Printing the resulting table is done once EOF/^D is reached.

[typecheck] has the following options: -c, -v

-c indicates "clear". This is for test programs (attempts were done to make it
work for regular programs but it didn't work).
    After EOF is reached -c makes it that the symbol table is to be cleared after each statement of input.
    Otherwise the symbol table is the same for all statements inputted.

-v indicates "verbose". This prints out the entire symbol table stack, even when
out of scope. It also indicates the current table in scope if it were to not be verbose.

Using the following code as an example:
foo: function integer(a: char) = {
    i: integer;
    return i;
}

  Normal output:

    SCOPE [0]: CURRENT (TOP) GLOBAL (BOTTOM)
--------------------------------------------------

foo --> (kind: global, name: foo, type: function integer (a: char))

--------------------------------------------------
Total errors: 0

Verbose output:

    SCOPE [2]:
--------------------------------------------------

i --> (kind: local, name: i, type: integer)

--------------------------------------------------
SCOPE [1]:
--------------------------------------------------

a --> (kind: parameter, name: a, type: char)

--------------------------------------------------
SCOPE [0]: CURRENT (TOP) GLOBAL (BOTTOM)
--------------------------------------------------

foo --> (kind: global, name: foo, type: function integer (a: char))

--------------------------------------------------
Total errors: 0

ERROR MESSAGES

This typechecker also has various error messages, grouped together based on the structures that trigger them: symbol_table, stmt, expr, and decl

These structures are used as prefixes for the error_handle() functions, which take the error kind and a various amount of void pointer parameters, acting as contexts. All of them return the passed in error kind as an error code.

int symbol_table_error_handle(symbol_error_t kind, void ctx1, void ctx2); int stmt_error_handle(stmt_error_t kind, void ctx1, void ctx2); int expr_error_handle(type_error_t kind, void ctx1, void type_ctx1, void ctx2, void type_ctx2); int decl_error_handel(decl_error_t kind, void ctx1, void ctx2);

All of these functions do is print the corresponding error message given the kind and context(s). Recovery may also be done. They also all increment the global error counter and print to file pointer stderr.

Symbol table errors:

Statement errors:

Expression (type) errors:

Declaration (array) errors:

Improvements can obviously be made, such as passing an array of pointers, only using one function, better naming, etc., but that is for another time.


SYMBOL TABLE The symbol table was implemented by using a 'generic' stack interface, where the hash tables to be used are cast as void pointers and vice versa. The symbol table itself is slightly more than just a stack, as instead of just a mere typedef, it is a struct:

struct symbol_table { Stack* stack; bool verbose; int top; }; typedef struct symbol_table Symbol_table;

The stack field is the actual table, but there are two additional fields:

The symbol table has the following functions available: (Further description/implementation can be read in source/symbol_table.h and source/symbol_table.c (and perhaps source/stack.h and source/stack.c as well!))

Construction/Destruction:

Mutation:

Retrieval:

Printing:


TESTS There are two test suites (in directory tests/symbol_table/): The executables can be run individually via [tests/test_stack] or [tests/test_typecheck] To run ALL tests run [test] (must be made via [make], [make all], or [make tests])

test_stack.c tests the symbol table structure

test_typecheck:


CAVEATS: