Skip to content

Commit

Permalink
adding workflows and README
Browse files Browse the repository at this point in the history
  • Loading branch information
nlsandler committed Aug 19, 2024
1 parent 66f0a12 commit 96fc325
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 0 deletions.
94 changes: 94 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Build tagged versions of the reference implementation compiler
name: Build the compiler

on:
workflow_dispatch:
inputs:
chapter:
required: true
type: string
os:
required: true
default: ubuntu-latest

workflow_call:
inputs:
chapter:
required: true
type: number
os:
type: string
required: true
default: ubuntu-latest
branch:
type: string
required: false
default: main

env:
EXE_DIR: _build/default/bin/
EXE_PATH: _build/default/bin/main.exe

jobs:

build:
runs-on: ${{ inputs.os }}
env:
CHAPTER: ${{ inputs.chapter }}

steps:

# first check out at specified branch so we can find commit hash for this chapter
- uses: actions/checkout@v4
with:
repository: nlsandler/nqcc2
ref: ${{ inputs.branch }}
fetch-depth: 0 # need this to get commit history

- name: Get commit hash
run: |
git log --grep "chapter $CHAPTER:" -i --format='%H'
commit=$(git log --grep "chapter $CHAPTER:" -i --format='%H')
echo "commit=$commit" >> $GITHUB_ENV
- name: Check out NQCC at chapter ${{ inputs.chapter }}
uses: actions/checkout@v4
with:
repository: nlsandler/nqcc2
ref: ${{ env.commit }}

- name: Construct cache key
id: make-key
env:
runner_os: ${{ runner.os }}
run: |
commit=$(git rev-parse --short "$commit")
echo "cache-key=${runner_os}-${commit}-nqcc" >> $GITHUB_OUTPUT
- name: Cache build result
id: cache-nqcc
uses: actions/cache@v4
with:
path: ${{ env.EXE_PATH }}
key: ${{ steps.make-key.outputs.cache-key }}

# skip building if we get a cache hit
- name: Set up OCaml
if: steps.cache-nqcc.outputs.cache-hit != 'true'
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: 4.14.x
# necessary to avoid random errors, see https://github.com/ocaml/setup-ocaml/issues/400
dune-cache: false

- name: Build it
if: steps.cache-nqcc.outputs.cache-hit != 'true'
run: |
opam install . --deps-only
opam exec -- dune build
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: nqcc-${{inputs.os}}-${{ inputs.chapter }}
path: ${{ env.EXE_PATH }}
70 changes: 70 additions & 0 deletions .github/workflows/build_and_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Build and test the compiler

on:
workflow_call:
inputs:
os:
required: true
type: string
chapter:
required: true
type: number

jobs:
build:
uses: nlsandler/nqcc2/.github/workflows/build.yaml@main
with:
chapter: ${{ inputs.chapter }}
os: ${{ inputs.os }}

test:
runs-on: ${{ inputs.os }}
needs: [build]
env:
CHAPTER: ${{ inputs.chapter }}
steps:

- name: Check out tests
uses: actions/checkout@v4
with:
repository: nlsandler/writing-a-c-compiler-tests
ref: complete-test-suite # TODO use main once this is merged

- name: Download the compiler
uses: actions/download-artifact@v4
with:
name: nqcc-${{inputs.os}}-${{ inputs.chapter }}
path: nqcc

# make NQCC executable
- run: chmod u+x nqcc/main.exe

# TODO handle intermediate stages w/in chapters 19, 20
- name: Test the lexer
if: inputs.chapter < 19
run: |
./test_compiler nqcc/main.exe --chapter "$CHAPTER" --stage lex
- name: Test the parser
if: inputs.chapter < 19
run: |
./test_compiler nqcc/main.exe --chapter "$CHAPTER" --stage parse
- name: Test validation
if: inputs.chapter < 19 && inputs.chapter > 4
run: |
./test_compiler nqcc/main.exe --chapter "$CHAPTER" --stage validate
- name: Test TACKY generation
if: inputs.chapter < 19 && inputs.chapter > 1
run: |
./test_compiler nqcc/main.exe --chapter "$CHAPTER" --stage tacky
- name: Test assembly generation
if: inputs.chapter < 19 && inputs.chapter > 1
run: |
./test_compiler nqcc/main.exe --chapter "$CHAPTER" --stage codegen
- name: Test the whole compiler
run: ./test_compiler nqcc/main.exe --chapter "$CHAPTER"

18 changes: 18 additions & 0 deletions .github/workflows/test_each_chapter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Build and test each chapter

on:
workflow_dispatch:

jobs:


build-and-test:
strategy:
fail-fast: true
matrix:
os: [macos-latest, ubuntu-latest]
chapter: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
uses: nlsandler/nqcc2/.github/workflows/build_and_test.yaml@main
with:
chapter: ${{ matrix.chapter }}
os: ${{ matrix.os }}
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# NQCC2, the Not-Quite-C Compiler

**CAUTION: FREQUENT FORCE PUSHES**

This is the reference implementation for the upcoming book [Writing a C Compiler](https://nostarch.com/writing-c-compiler), a hands-on guide to writing your own compiler for a big chunk of C.

Each commit corresponds to one chapter in the book, to illustrate what needs to change at each step. Because commits are structured this way, this repository sees frequent rebases and force pushes - fork with caution!

This implementation is still a work in progress - the functionality is complete, but needs more work on the readability front.

# Building the Compiler

This compiler is written in OCaml. Building it requires opam, the OCaml package manager (installation instructions [here](https://opam.ocaml.org/doc/Install.html)).

Then do:

```
git clone https://github.com/nlsandler/nqcc2.git
cd nqcc2
opam install . --deps-only
dune build
```

This puts the executable at `_build/default/bin/main.exe`.

# Usage Example

Assume we have this source file at ~/hello_world.c:
```c
int puts(char *c);

int main(void) {
puts("Hello, world!");
}
```
To compile and run it:
```
$ _build/default/bin/main.exe ~/hello_world.c
$ ~/hello_world
Hello, World!
```

0 comments on commit 96fc325

Please sign in to comment.