SOMEHOW IT WORKS

This commit is contained in:
2026-01-25 20:58:36 -05:00
commit e5e75b344f
187 changed files with 1412 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

16
Makefile Normal file
View File

@@ -0,0 +1,16 @@
.PHONY: build run clean release test
build:
swift build
release:
swift build -c release
run:
swift run
test:
swift test
clean:
swift package clean

15
Package.swift Normal file
View File

@@ -0,0 +1,15 @@
// swift-tools-version: 6.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "rxcc",
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.executableTarget(
name: "rxcc"
),
]
)

153
Sources/rxcc/rxcc.swift Normal file
View File

@@ -0,0 +1,153 @@
enum Constant {
case Integer(value: Int)
}
struct Return {
let value: Constant
}
struct Function {
let name: String
let statement: Return
}
struct Program {
let contents: Function
}
enum TokenType {
case BRACE_OPEN
case BRACE_CLOSE
case PARENTHESIS_OPEN
case PARENTHESIS_CLOSE
case SEMICOLON
case INT
case RETURN
case IDENTIFIER
case LITERAL_INTEGER
case UNDEFINED
}
struct Token {
let content: Substring
let type: TokenType
}
typealias Construct = [Element]
enum Element {
case Construct(type: Construct)
case Token(type: TokenType)
}
let expression: Construct = [
.Token(type: .LITERAL_INTEGER)
]
let statement: Construct = [
.Token(type: .RETURN),
.Construct(type: expression),
.Token(type: .SEMICOLON)
]
let function: Construct = [
.Token(type: .INT),
.Token(type: .IDENTIFIER),
.Token(type: .PARENTHESIS_OPEN),
.Token(type: .PARENTHESIS_CLOSE),
.Token(type: .BRACE_OPEN),
.Construct(type: statement),
.Token(type: .BRACE_CLOSE)
]
let program: Construct = [
.Construct(type: function)
]
@main
struct rxcc {
static func main() {
let lexed: [Substring] = lex(string: """
int main() {
return 100;
}
""")
parse(lexed: lexed)
}
}
func lex(string: String) -> [Substring] {
var line = string.replacing("\n", with: " ")
line = line.replacing("\t", with: " ")
line = line.replacing("{", with: " { ")
line = line.replacing("}", with: " } ")
line = line.replacing("(", with: " ( ")
line = line.replacing(")", with: " ) ")
line = line.replacing(";", with: " ; ")
do {
let tokens: [Substring] = line.split(separator: try Regex(" +"))
return tokens
} catch {
print("Regex did something wrong")
}
return []
}
func parse(lexed: [Substring]) {
var tokens: [Token] = [Token]()
for token: Substring in lexed {
let tokenType: TokenType = categorizeToken(token: token)
tokens.append(Token(content: token, type: tokenType))
}
tokens = tokens.reversed()
if validateConstruct(program, tokens: &tokens) {
print("Success")
return
}
print("Distinct lack of success")
}
func validateConstruct(_ construct: Construct, tokens: inout [Token]) -> Bool {
for element in construct {
switch element {
case .Construct(let type):
print("Begin validate subconstruct")
if !validateConstruct(type, tokens: &tokens) {
print("Subconstruct validation failed")
return false
}
print("End validate subconstruct")
break
case .Token(let type):
if let token: Token = tokens.popLast() {
if type != token.type {
print("VALIDATION FAILED FOR TOKEN \"\(token.content)\"")
return false
}
}
}
}
return true
}
func categorizeToken(token: Substring) -> TokenType {
if token.firstMatch(of: /{/) != nil { return .BRACE_OPEN }
else if token.firstMatch(of: /}/) != nil { return .BRACE_CLOSE }
else if token.firstMatch(of: /\(/) != nil { return .PARENTHESIS_OPEN }
else if token.firstMatch(of: /\)/) != nil { return .PARENTHESIS_CLOSE }
else if token.firstMatch(of: /;/) != nil { return .SEMICOLON }
else if token.firstMatch(of: /int/) != nil { return .INT }
else if token.firstMatch(of: /return/) != nil { return .RETURN }
else if token.firstMatch(of: /[a-zA-Z]\w*/) != nil { return .IDENTIFIER }
else if token.firstMatch(of: /[0-9]+/) != nil { return .LITERAL_INTEGER }
return .UNDEFINED
}

BIN
c/a.out Executable file

Binary file not shown.

BIN
c/return_2 Executable file

Binary file not shown.

4
c/return_2.c Normal file
View File

@@ -0,0 +1,4 @@
int main() {
return 2;
}

35
c/return_2.s Normal file
View File

@@ -0,0 +1,35 @@
.file "return_2.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
call __x86.get_pc_thunk.ax
addl $_GLOBAL_OFFSET_TABLE_, %eax
movl $2, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
.globl __x86.get_pc_thunk.ax
.hidden __x86.get_pc_thunk.ax
.type __x86.get_pc_thunk.ax, @function
__x86.get_pc_thunk.ax:
.LFB1:
.cfi_startproc
movl (%esp), %eax
ret
.cfi_endproc
.LFE1:
.ident "GCC: (GNU) 15.2.1 20260103"
.section .note.GNU-stack,"",@progbits

158
c/test_compiler.sh Executable file
View File

@@ -0,0 +1,158 @@
#!/bin/bash
padding_dots=$(printf '%0.1s' "."{1..60})
padlength=50
cmp=$1
success_total=0
failure_total=0
print_test_name () {
test_name=$1
printf '%s' "$test_name"
printf '%*.*s' 0 $((padlength - ${#test_name})) "$padding_dots"
}
test_success () {
echo "OK"
((success++))
}
test_failure () {
echo "FAIL"
((fail++))
}
test_not_implemented () {
echo "NOT IMPLEMENTED"
}
run_our_program () {
actual_out=`./$1 2>/dev/null`
actual_exit_code=$?
rm $1 2>/dev/null
}
run_correct_program () {
expected_out=`./a.out`
expected_exit_code=$?
rm a.out
}
compare_program_results () {
# make sure exit code is correct
if [ "$expected_exit_code" -ne "$actual_exit_code" ] || [ "$expected_out" != "$actual_out" ]
then
test_failure
else
test_success
fi
}
test_stage () {
success=0
fail=0
echo "===================================================="
echo "STAGE $1"
echo "===================Valid Programs==================="
for prog in `find . -type f -name "*.c" -path "./stage_$1/valid/*" -not -path "*/valid_multifile/*" 2>/dev/null`; do
gcc -w $prog
run_correct_program
base="${prog%.*}" #name of executable (filename w/out extension)
test_name="${base##*valid/}"
print_test_name $test_name
$cmp $prog 2>/dev/null
status=$?
if [[ $test_name == "skip_on_failure"* ]]; then
# this may depend on features we haven't implemented yet
# if compilation succeeds, make sure it gives the right result
# otherwise don't count it as success or failure
if [[ -f $base ]] && [[ $status -eq 0 ]]; then
# it succeeded, so run it and make sure it gives the right result
run_our_program $base
compare_program_results
else
test_not_implemented
fi
else
run_our_program $base
compare_program_results
fi
done
# programs with multiple source files
for dir in `ls -d stage_$1/valid_multifile/* 2>/dev/null` ; do
gcc -w $dir/*
run_correct_program
base="${dir%.*}" #name of executable (directory w/out extension)
test_name="${base##*valid_multifile/}"
# need to explicitly specify output name
$cmp -o "$test_name" $dir/* >/dev/null
print_test_name $test_name
# check output/exit codes
run_our_program $test_name
compare_program_results
done
echo "===================Invalid Programs================="
for prog in `ls stage_$1/invalid/{,**/}*.c 2>/dev/null`; do
base="${prog%.*}" #name of executable (filename w/out extension)
test_name="${base##*invalid/}"
$cmp $prog >/dev/null 2>&1
status=$? #failed, as we expect, if exit code != 0
print_test_name $test_name
# make sure neither executable nor assembly was produced
# and exit code is non-zero
if [[ -f $base || -f $base".s" ]]
then
test_failure
rm $base 2>/dev/null
rm $base".s" 2>/dev/null
else
test_success
fi
done
echo "===================Stage $1 Summary================="
printf "%d successes, %d failures\n" $success $fail
((success_total=success_total+success))
((failure_total=failure_total + fail))
}
total_summary () {
echo "===================TOTAL SUMMARY===================="
printf "%d successes, %d failures\n" $success_total $failure_total
}
if [ "$1" == "" ]; then
echo "USAGE: ./test_compiler.sh /path/to/compiler [stages(optional)]"
echo "EXAMPLE(test specific stages): ./test_compiler.sh ./mycompiler 1 2 4"
echo "EXAMPLE(test all): ./test_compiler.sh ./mycompiler"
exit 1
fi
if test 1 -lt $#; then
testcases=("$@") # [1..-1] is testcases
for i in `seq 2 $#`; do
test_stage ${testcases[$i-1]}
done
total_summary
exit 0
fi
num_stages=10
for i in `seq 1 $num_stages`; do
test_stage $i
done
total_summary

View File

@@ -0,0 +1,3 @@
int main( {
return 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return;
}

View File

@@ -0,0 +1,2 @@
int main() {
return 0;

View File

@@ -0,0 +1,3 @@
int main() {
return 0
}

View File

@@ -0,0 +1,3 @@
int main() {
return0;
}

View File

@@ -0,0 +1,3 @@
int main() {
RETURN 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 100;
}

View File

@@ -0,0 +1,10 @@
int
main
(
)
{
return
0
;
}

View File

@@ -0,0 +1 @@
int main(){return 0;}

View File

@@ -0,0 +1,3 @@
int main() {
return 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2;
}

View File

@@ -0,0 +1 @@
int main ( ) { return 0 ; }

View File

@@ -0,0 +1,9 @@
int foo() {
return 3;
}
int foo = 4;
int main() {
return foo;
}

View File

@@ -0,0 +1,7 @@
int foo = 3;
int main() {
return foo;
}
int foo = 0;

View File

@@ -0,0 +1,6 @@
int foo = 3;
int bar = foo + 1;
int main() {
return bar;
}

View File

@@ -0,0 +1,5 @@
int main() {
return foo;
}
int foo = 3;

View File

@@ -0,0 +1,9 @@
int foo = 4;
int foo() {
return 3;
}
int main() {
return foo;
}

View File

@@ -0,0 +1,5 @@
int foo = 3;
int main() {
return foo();
}

View File

@@ -0,0 +1,7 @@
int foo;
int main() {
return foo;
}
int foo = 3;

View File

@@ -0,0 +1,8 @@
int foo() {
return 3;
}
int main() {
int foo = 5;
return foo;
}

View File

@@ -0,0 +1,5 @@
int foo = 4;
int main() {
return foo + 3;
}

View File

@@ -0,0 +1,7 @@
int foo;
int main() {
for (int i = 0; i < 3; i = i + 1)
foo = foo + 1;
return foo;
}

View File

@@ -0,0 +1,10 @@
int a = 3;
int main() {
int ret = 0;
if (a) {
int a = 0;
ret = 4;
}
return ret;
}

View File

@@ -0,0 +1,6 @@
int a = 3;
int b = 4;
int main() {
return a * b;
}

View File

@@ -0,0 +1,3 @@
int main() {
return !;
}

View File

@@ -0,0 +1,3 @@
int main() {
return !5
}

View File

@@ -0,0 +1,3 @@
int main() {
return !~;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 4-;
}

View File

@@ -0,0 +1,3 @@
int main() {
return ~12;
}

View File

@@ -0,0 +1,3 @@
int main() {
return ~0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return -5;
}

View File

@@ -0,0 +1,3 @@
int main() {
return !-3;
}

View File

@@ -0,0 +1,3 @@
int main() {
return -~0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return !5;
}

View File

@@ -0,0 +1,3 @@
int main() {
return !0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2 (- 3);
}

View File

@@ -0,0 +1,3 @@
int main() {
return /3;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 + ;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2*2
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 + 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 - 2 - 3;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 6 / 3 / 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 4 / 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return (-12) / 5;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2 * 3;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2 * (3 + 4);
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2 + 3 * 4;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 - 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2- -1;
}

View File

@@ -0,0 +1,3 @@
int main() {
return ~2 + 3;
}

View File

@@ -0,0 +1,3 @@
int main() {
return ~(1 + 1);
}

View File

@@ -0,0 +1,3 @@
int main() {
return <= 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 < > 3;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2 &&
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 || 2
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 && 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 && -1;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 == 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 == 1;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 >= 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 >= 1;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 > 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 > 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 <= -1;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 0 <= 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2 < 1;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 < 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 0 != 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return -1 != -2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 0 || 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 || 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 1 || 0 && 2;
}

View File

@@ -0,0 +1,3 @@
int main() {
return (1 || 0) && 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2 == 2 > 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
return 2 == 2 || 0;
}

View File

@@ -0,0 +1,5 @@
int main() {
int a = 0;
a || (a = 3) || (a = 4);
return a;
}

View File

@@ -0,0 +1,6 @@
int main() {
int a = 0;
int b = 0;
a && (b = 5);
return b;
}

View File

@@ -0,0 +1,6 @@
int main() {
int a = 1;
int b = 0;
a || (b = 5);
return b;
}

View File

@@ -0,0 +1,5 @@
int main() {
int a = 1;
int a = 2;
return a;
}

View File

@@ -0,0 +1,4 @@
int main() {
ints a = 1;
return a;
}

View File

@@ -0,0 +1,4 @@
int main() {
int foo bar = 3;
return bar;
}

View File

@@ -0,0 +1,5 @@
int main() {
int a = 2;
a + 3 = 4;
return a;
}

View File

@@ -0,0 +1,5 @@
int main() {
int a = 2;
!a = 3;
return a;
}

View File

@@ -0,0 +1,5 @@
int main() {
int a = 2
a = a + 4;
return a;
}

View File

@@ -0,0 +1,3 @@
int main() {
return a;
}

View File

@@ -0,0 +1,5 @@
int main() {
a = 1 + 2;
int a;
return a;
}

View File

@@ -0,0 +1,5 @@
int main() {
int a;
a = 2;
return a;
}

View File

@@ -0,0 +1,5 @@
int main() {
int a;
int b = a = 0;
return b;
}

View File

@@ -0,0 +1,6 @@
int main() {
int a;
int b;
a = b = 4;
return a - b;
}

View File

@@ -0,0 +1,4 @@
int main() {
int a = 2;
return 0;
}

View File

@@ -0,0 +1,3 @@
int main() {
}

Some files were not shown because too many files have changed in this diff Show More