Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
.*
*~
# Generated host frontend and build products
/build/

# Python bytecode caches
__pycache__/
*.py[cod]

# Legacy generated frontend files
lex.yy.c
lex
y.tab.c
y.tab.h
y.output
# except for .gitignore
!.gitignore
final
*.o
*.d

# Compiler artifacts and dumps
*.adi
*.elf
*.s
*.S.tmp
*.ast
*.sem
*.ir
*.asm
122 changes: 92 additions & 30 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,41 +1,103 @@
final: y.tab.o lex.yy.o errormsg.o util.o absyn.o symbol.o table.o prabsyn.o type.o
cc -g y.tab.o lex.yy.o errormsg.o util.o absyn.o symbol.o table.o prabsyn.o type.o -o final -lm
CC ?= cc
FLEX ?= flex
BISON ?= bison
PYTHON ?= python3

y.tab.o: y.tab.c
cc -g -c y.tab.c
BUILD_DIR := build
BIN_DIR := $(BUILD_DIR)/bin
GEN_DIR := $(BUILD_DIR)/generated
OBJ_DIR := $(BUILD_DIR)/obj
ADAC := $(BIN_DIR)/adac

y.tab.c: parser.y
yacc --debug -vd parser.y
CPPFLAGS := -D_POSIX_C_SOURCE=200809L -I. -I$(GEN_DIR)
CFLAGS := -std=c11 -g -O0 -Wall -Wextra -Wpedantic -Werror
LDLIBS := -lm

y.tab.h: y.tab.c
echo "y.tab.h was created at the same time as y.tab.c"
PARSER_C := $(GEN_DIR)/parser.c
PARSER_H := $(GEN_DIR)/parser.h
PARSER_REPORT := $(GEN_DIR)/parser.output
LEXER_C := $(GEN_DIR)/lexer.c

errormsg.o: errormsg.c errormsg.h util.h
cc -g -c errormsg.c
HOST_SOURCES := driver.c compile.c errormsg.c util.c absyn.c symbol.c table.c prabsyn.c type.c
HOST_OBJECTS := $(HOST_SOURCES:%.c=$(OBJ_DIR)/%.o)
GENERATED_OBJECTS := $(OBJ_DIR)/parser.o $(OBJ_DIR)/lexer.o
OBJECTS := $(HOST_OBJECTS) $(GENERATED_OBJECTS)

lex.yy.o: lex.yy.c y.tab.h errormsg.h util.h
cc -g -c lex.yy.c
.PHONY: all strict clean test host-tools coverage contract

lex.yy.c: lexer.l
lex lexer.l
# Build only: validation is deliberately reserved for `make strict`.
all: $(ADAC)

util.o: util.c util.h
cc -g -c util.c
strict: host-tools all coverage contract

absyn.o: absyn.c absyn.h
cc -g -c absyn.c
$(ADAC): $(OBJECTS) | $(BIN_DIR)
$(CC) $(CFLAGS) $(OBJECTS) $(LDLIBS) -o $@

prabsyn.o: prabsyn.c prabsyn.h
cc -g -c prabsyn.c

symbol.o: symbol.c symbol.h
cc -g -c symbol.c
$(PARSER_C) $(PARSER_H) $(PARSER_REPORT) &: parser.y | $(GEN_DIR)
$(BISON) --defines=$(PARSER_H) --output=$(PARSER_C) --report=all --report-file=$(PARSER_REPORT) parser.y

table.o: table.c table.h
cc -g -c table.c
$(LEXER_C): lexer.l $(PARSER_H) | $(GEN_DIR)
$(FLEX) --outfile=$@ lexer.l

type.o: type.c type.h
cc -g -c type.c

clean:
rm -f final *.o lex.yy.c y.tab.c y.tab.h y.output
$(OBJ_DIR)/%.o: %.c | $(OBJ_DIR)
@mkdir -p $(@D)
$(CC) $(CPPFLAGS) $(CFLAGS) -MMD -MP -c $< -o $@

$(OBJ_DIR)/parser.o: $(PARSER_C) | $(OBJ_DIR)
@mkdir -p $(@D)
$(CC) $(CPPFLAGS) $(CFLAGS) -Wno-unused-function -MMD -MP -c $< -o $@

$(OBJ_DIR)/lexer.o: $(LEXER_C) | $(OBJ_DIR)
@mkdir -p $(@D)
$(CC) $(CPPFLAGS) $(CFLAGS) -Wno-unused-function -MMD -MP -c $< -o $@

$(BIN_DIR) $(GEN_DIR) $(OBJ_DIR):
mkdir -p $@

host-tools:
@command -v $(CC) >/dev/null || { echo "missing host C compiler: $(CC)" >&2; exit 1; }
@command -v $(FLEX) >/dev/null || { echo "missing flex: $(FLEX)" >&2; exit 1; }
@command -v $(BISON) >/dev/null || { echo "missing bison: $(BISON)" >&2; exit 1; }
@command -v $(PYTHON) >/dev/null || { echo "missing Python: $(PYTHON)" >&2; exit 1; }
@$(FLEX) --version | grep -F 'flex 2.6.4' >/dev/null || { echo "expected flex 2.6.4" >&2; exit 1; }
@$(BISON) --version | head -n 1 | grep -F '3.8.2' >/dev/null || { echo "expected bison 3.8.2" >&2; exit 1; }

coverage:
$(PYTHON) tools/inventory_grammar.py --check-baseline
$(PYTHON) tools/check_coverage.py

contract:
$(PYTHON) tests/run_tests.py

clean:
rm -rf $(BUILD_DIR)

test: $(ADAC)
@set -eu; \
workdir=$$(mktemp -d "$${TMPDIR:-/tmp}/adac-host-test.XXXXXX"); \
trap 'rm -rf "$$workdir"' EXIT HUP INT TERM; \
printf 'procedure Empty is\nbegin\n null;\nend Empty;\n' > "$$workdir/empty.adb"; \
printf 'procedure Token_Test is\n type T is null record;\n V : Integer := 16#fF#;\nbegin\n for I in reverse 1 .. 1 loop\n null;\n end loop;\nend Token_Test;\n' > "$$workdir/token.adb"; \
$(ADAC) --help > "$$workdir/help"; \
grep -F 'usage: adac <check|compile|build>' "$$workdir/help" >/dev/null; \
$(ADAC) check "$$workdir/empty.adb"; \
$(ADAC) check "$$workdir/token.adb"; \
printf 'private procedure Private_Unit is\nbegin\n null;\nend Private_Unit;\n' > "$$workdir/private.adb"; \
$(ADAC) check --emit-ast "$$workdir/private.adb" > "$$workdir/private.ast"; \
grep -F 'stringExp(private)' "$$workdir/private.ast" >/dev/null; \
$(ADAC) check --emit-ast --emit-sem --emit-ir --emit-asm "$$workdir/empty.adb" > "$$workdir/dumps"; \
grep -F 'semantic dump unavailable in R0' "$$workdir/dumps" >/dev/null; \
if $(ADAC) compile -o "$$workdir/out.o" "$$workdir/empty.adb" > "$$workdir/compile.out" 2> "$$workdir/compile.err"; then exit 1; fi; \
grep -F 'unsupported-in-release: compile phase is not available in R0' "$$workdir/compile.err" >/dev/null; \
test ! -e "$$workdir/out.o"; \
printf 'procedure Bad is begin\n' > "$$workdir/bad.adb"; \
if $(ADAC) check "$$workdir/bad.adb" > "$$workdir/bad.out" 2> "$$workdir/bad.err"; then exit 1; fi; \
grep -F "$$workdir/bad.adb:2:1: error: syntax error" "$$workdir/bad.err" >/dev/null; \
printf 'procedure Broken is\n @\nbegin\n null;\nend Broken;\n' > "$$workdir/line-column.adb"; \
if $(ADAC) check "$$workdir/line-column.adb" > "$$workdir/line-column.out" 2> "$$workdir/line-column.err"; then exit 1; fi; \
grep -F "$$workdir/line-column.adb:2:3: error: Illegal token" "$$workdir/line-column.err" >/dev/null; \
if $(ADAC) check "$$workdir/missing.adb" > "$$workdir/missing.out" 2> "$$workdir/missing.err"; then exit 1; fi; \
grep -F 'No such file or directory' "$$workdir/missing.err" >/dev/null; \
$(ADAC) check "$$workdir/empty.adb"

-include $(OBJECTS:.o=.d)
60 changes: 56 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,56 @@
ada-compiler
============
Course Project for CS335.
*This project is no longer maintained.*
# Ada compiler restoration

This repository is being restored as a staged Ada compiler targeting static
Linux MIPS32r2 executables. R0 provides a deterministic host frontend build and
an honest command-line foundation; target code generation and semantic analysis
are release-owned work that is not yet available.

## Host prerequisites

- C11 compiler
- GNU Make
- Flex 2.6.4
- Bison 3.8.2

Build the host driver with:

```sh
make strict
```

Generated lexer/parser files, objects, dependency files, and the executable are
contained under `build/`; source files are never regenerated in place.

## CLI

```text
adac check [--emit-ast] [--emit-sem] [--emit-ir] [--emit-asm] SOURCE
adac compile [--unit-dir DIR] [-o PATH] SOURCE
adac build [--unit-dir DIR] [-o PATH] SOURCE
```

Use `build/bin/adac --help` for the full option list.

- `check` parses the source and returns a nonzero status for input or syntax
diagnostics.
- `compile` and `build` parse successfully but return a stable
`unsupported-in-release` diagnostic in R0. They intentionally leave no output
artifacts.
- `--emit-ast` dumps the current frontend AST. Semantic, IR, and assembly dumps
explicitly report their R0-unavailable status rather than pretending to
produce later-phase output.
- Based-literal digits are case-insensitive (`16#fF#` is accepted); spelling is
otherwise preserved by the lexer for later syntax diagnostics and dumps.

## Validation

```sh
make strict
make test
```

`make strict` validates host tools, the grammar-coverage baseline and manifest,
and the direct Linux/MIPS ELF/QEMU/ABI contract. `make test` runs the focused
host CLI smoke coverage: help, valid input, malformed input, missing input,
unsupported phases, dump flags, and repeated invocations. `make all` is
build-only.
11 changes: 4 additions & 7 deletions absyn.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* absyn.c - Abstract Syntax Functions. Most functions create an instance of an
* abstract syntax rule.
*/
#include <stdio.h>
#include "util.h"
#include "symbol.h" /* symbol table data structures */
#include "absyn.h" /* abstract syntax data structures */
Expand Down Expand Up @@ -58,13 +57,11 @@ A_exp A_NumberExp(A_pos pos, string s)
return p;
}

A_exp A_StringExp(A_pos pos, S_table table, string s)
A_exp A_StringExp(A_pos pos, string s)
{A_exp p = checked_malloc(sizeof(*p));
p->kind=A_stringExp;
p->pos=pos;
A_ty t=S_look(table,S_Symbol(s));
if(t==NULL) p->dec_type=S_Symbol(s);
else p->dec_type=t->dec_type;
p->dec_type=S_Symbol(s);
p->u.stringg=s;
return p;
}
Expand Down Expand Up @@ -456,7 +453,7 @@ A_dec A_VarDec(A_pos pos, S_symbol var, S_symbol typ, A_exp init)
p->u.var.var=var;
p->u.var.typ=typ;
p->u.var.init=init;
p->u.var.escape=TRUE;
p->u.var.escape=true;
return p;
}

Expand Down Expand Up @@ -532,7 +529,7 @@ A_field A_Field(A_pos pos, S_symbol name, S_symbol typ)
p->pos=pos;
p->name=name;
p->typ=typ;
p->escape=TRUE;
p->escape=true;
return p;
}

Expand Down
9 changes: 8 additions & 1 deletion absyn.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
* Linked list types end with "..list"
*/

#ifndef ADA_ABSYN_H
#define ADA_ABSYN_H

#include "symbol.h"

/* Type Definitions */

typedef int A_pos;
Expand Down Expand Up @@ -155,7 +160,7 @@ A_var A_SubscriptVar(A_pos pos, A_var var, A_exp exp);
A_exp A_VarExp(A_pos pos, A_var var);
A_exp A_NilExp(A_pos pos);
A_exp A_NumberExp(A_pos pos, string number);
A_exp A_StringExp(A_pos pos, S_table table, string s);
A_exp A_StringExp(A_pos pos, string s);
A_exp A_CallExp(A_pos pos, S_symbol func, A_expList args);
A_exp A_OpExp(A_pos pos, A_oper oper, A_exp left, A_exp right);
A_exp A_UnaryOpExp(A_pos pos, A_unaryOper oper, A_exp exp);
Expand Down Expand Up @@ -217,3 +222,5 @@ A_namety A_Namety(S_symbol name, A_ty ty);
A_nametyList A_NametyList(A_namety head, A_nametyList tail);
A_efield A_Efield(S_symbol name, A_exp exp);
A_efieldList A_EfieldList(A_efield head, A_efieldList tail);

#endif
23 changes: 23 additions & 0 deletions ci/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# syntax=docker/dockerfile:1
FROM ubuntu:24.04

ARG DEBIAN_FRONTEND=noninteractive

# Keep the target development libc deliberately absent. The runtime is linked
# with ld directly, so accidentally introducing a CRT, libc, or libgcc object
# becomes a link failure rather than a host-dependent success.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bison=2:3.8.2+dfsg-1build2 \
flex=2.6.4-8.2build1 \
gcc=4:13.2.0-7ubuntu1 \
make=4.3-4.1build2 \
gcc-13-mipsel-linux-gnu=13.3.0-6ubuntu2~24.04cross1 \
binutils-mipsel-linux-gnu=2.42-2ubuntu1cross5 \
qemu-user=1:8.2.2+ds-0ubuntu1.17 \
linux-libc-dev-mipsel-cross=6.8.0-25.25cross2 \
gnat-13=13.3.0-6ubuntu2~24.04.1 \
python3 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /work
34 changes: 34 additions & 0 deletions ci/toolchain.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# R0 Linux/mipsel toolchain lock
#
# Distribution: Ubuntu 24.04 (Noble)
# This lock intentionally does not contain libc6-dev-mipsel-cross. The
# compiler-owned runtime must remain freestanding and link without target CRT,
# libc, or libgcc objects.

HOST_CC=gcc
HOST_CC_PACKAGE=gcc=4:13.2.0-7ubuntu1
MAKE_PACKAGE=make=4.3-4.1build2
FLEX_PACKAGE=flex=2.6.4-8.2build1
BISON_PACKAGE=bison=2:3.8.2+dfsg-1build2
GNAT_PACKAGE=gnat-13=13.3.0-6ubuntu2~24.04.1
PYTHON_PACKAGE=python3

TARGET_TRIPLE=mipsel-linux-gnu
TARGET_CC=mipsel-linux-gnu-gcc-13
TARGET_CC_PACKAGE=gcc-13-mipsel-linux-gnu=13.3.0-6ubuntu2~24.04cross1
TARGET_BINUTILS_PACKAGE=binutils-mipsel-linux-gnu=2.42-2ubuntu1cross5
TARGET_AS=mipsel-linux-gnu-as
TARGET_LD=mipsel-linux-gnu-ld
TARGET_NM=mipsel-linux-gnu-nm
TARGET_READELF=mipsel-linux-gnu-readelf
TARGET_OBJDUMP=mipsel-linux-gnu-objdump
QEMU=qemu-mipsel
QEMU_PACKAGE=qemu-user=1:8.2.2+ds-0ubuntu1.17
TARGET_LINUX_HEADERS_PACKAGE=linux-libc-dev-mipsel-cross=6.8.0-25.25cross2
TARGET_UNISTD=/usr/mipsel-linux-gnu/include/asm/unistd.h

# These are individual argument lists rather than implicit compiler defaults.
TARGET_AS_FLAGS=-EL -32 -mips32r2 -mhard-float -mfp32 -mnan=legacy
TARGET_CFLAGS=-march=mips32r2 -mabi=32 -EL -mhard-float -mfp32 -mnan=legacy -fno-pic -mno-abicalls -G0 -ffreestanding -fno-stack-protector -fno-builtin -Wall -Wextra -Werror
TARGET_LD_FLAGS=-m elf32ltsmip -EL -static -T runtime/mipsel-linux.ld -e _start --orphan-handling=error
EXPECTED_E_FLAGS=0x70001001
Loading