simple, C-like programming language

Related tags

Miscellaneous cup
Overview

CUP: C(ompiler) U(nder) P(rogress)

A badly named, in-progress programming language just to learn how these things work. Wait, doesn't everyone write a compiler when they're bored?

Currently, the language is comparable to C, with some syntax changes inspired by Rust (that also make it a little easier to parse). The compiler outputs assembly code in yasm format, so you will need yasm and a linker of your choice to compile it. The included Makefile and scripts use ld. (Alternatively, you can use nasm, but you will have to change the command being run in compiler/main.cup and meta/bootstrap.sh)

Only linux and macOS (only on x86_64) are supported.

Building

Tools

Make sure you have yasm and ld installed, and located on your PATH.

Compiling

The reference implementation of the compiler is written in CUP, so you'll need to use the pre-compiled YASM files to get the initial executable. You should be able to run the command below to create the ./build/cupcc compiler:

$ ./meta/bootstrap.sh

Compile a program (and optionally run it) using:

$ ./build/cupcc /path/to/program.cup -o prog
$ ./prog 1 2 3 4
# OR
$ ./build/cupcc /path/to/program.cup -o prog -r 1 2 3 4

Make sure to not have the executable name end in .yasm or .o, since there are some temporary files created during compilation.


Code Samples

Hello World

Some common functions you'll want are located in std/common.cup

import "std/common.cup";

fn main(arc: int, argv: char**): int {
    putsln("Hello, world!");
    return 0;
}

Variables

Variables are strongly typed. You can either declare them with a type, or they can be inferred if there is an initial assignment.

fn main() {
    let x: int = 5;  // Explicity define the type
    let y = 6;       // Infer the type
    let z = x + y;   // Add them, and infer the type
}

Pointers and arrays

fn main() {
    let x: int[10];  // An array of 10 ints (initializers not supported)
    let y: int* = x; // Automatically decays to a pointer when passed or assigned
    let z = y;       // type(z) == int* also works
    
    let a = x[0];    // Access the first element (`a` is an int)
    let b = *(x+1);  // Access the second element (can use pointer arithmetic)
}

Structs / Unions / Enums

// For now, enums just generate constant values with sequential numbers.
// They aren't a "type" on their own.
enum Type {
    TypeInt,
    TypeFloat,
    TypeChar,
}

struct Variable {
    typ: int;        // Can't use `Type` here, because it's not a type
    value: union {   // Anonymous nested structures are allowed.
        as_int: int;
        as_char: char;
        as_ptr: Variable*;  // Can recursively define types.
    };
};

fn main() {
    let x: Variable; // No struct initializers yet
    x.typ = TypeInt;
    x.value.as_int = 5;
}

Methods for Structs/Unions

struct Value {
    x: int;
};

method Value::inc(amount: int) {
    // self (pointer) is implicitly passed in
    self.x = self.x + amount;
}

method Value::print() {
    print(self.x);
}

fn main() {
    let v: Value;
    let v_ptr = &v;

    v.x = 0;
    // Call methods using `::`
    v::inc(10);
    v_ptr::print(); // Also works for pointers
}

File I/O

For now, the file I/O is very inspired by C, but it's wrapped using methods for the File object. Optionally, you can use the raw syscalls (which behave like C), to deal with file descriptors manually. However it's preferred to use the File object as it's more convenient and also provides buffered writes.

A simple implementation of cat is:

0) { write(0, buf, n); // Use raw system calls n = file::read(buf, 1024); } // file closed here because of defer } }">
import "std/file.cup";

fn main(argc: int, argv: char**) {
    for (let i = 1; i < argc; ++i) {
        let file = fopen(argv[i], 'r');
        defer file::close();    // Close the file at the end of the block (in each iteration)

        let buf: char[1024];
        let n = file::read(buf, 1024); // use file-specific functions
        while (n > 0) {
            write(0, buf, n); // Use raw system calls
            n = file::read(buf, 1024);
        }
        // file closed here because of defer
    }
}

Want some more examples? Check out the examples directory, or the compiler directory, which contains the implementation of the compiler itself.

Comments
  • Implemented struct constructors

    Implemented struct constructors

    Hello again. Implemented Java like struct constructors which work like that:

    import "std/memory.cup"
    
    struct Foo{
    	i: i32;
    }
    
    Foo(a: i32){
    	let ptr: Foo* = malloc(sizeof(Foo));
    	ptr.i = a;
    	return ptr;
    }
    
    fn main(){
    	let a: Foo* = new Foo(5);
    	print(a.i);
    }
    
    opened by Weltspear 33
  • Cannot build on macOS BigSur version11.6

    Cannot build on macOS BigSur version11.6

    Build Issue Environment macOS BigSur version 11.6

    Description I was trying to follow the installation guide. I can't seem to build it on macOS BigSur.

    What I did First of all, I googled this error.

    $ ./meta/bootstrap.sh
    [+] Compiling the bootstrap compiler...
    ld: dynamic main executables must link with libSystem.dylib for architecture x86_64
    

    https://stackoverflow.com/a/65570573

    In accordance with this, fixed. (meta/bootstrap.sh)

       Darwin)
            cp bootstrap/macos.yasm bootstrap/cupcc.yasm
            yasm -f macho64 -o bootstrap/cupcc.o bootstrap/cupcc.yasm
            ld -o bootstrap/cupcc bootstrap/cupcc.o -macosx_version_min 11.6 -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lSystem
            ;;
    

    Then, I cannnot fix the next error.

    $ ./meta/bootstrap.sh
    [+] Compiling the bootstrap compiler...
    ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, but used in func_die from bootstrap/cupcc.o. To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie
    [+] Creating build/cupcc with bootstrap compiler...
    [+] /usr/local/bin/yasm -fmacho64 -o build/cupcc.o build/cupcc.yasm
    [+] /usr/bin/ld -o build/cupcc build/cupcc.o -lSystem
    ld: library not found for -lSystem
    std/common.cup:350:14: Child exited with non-zero status: (1)
    
    opened by yu1hpa 2
  • May I have the change to get the source code?

    May I have the change to get the source code?

    Thanks for your great work. I would like to get the source code which produce the bootstrap assembly code.

    Maybe you write the bootstrap code in C, Rust ..

    Thanks.

    opened by Lisprez 2
  • initial support for invoking yasm/ld anywhere in PATH

    initial support for invoking yasm/ld anywhere in PATH

    Leverages /usr/bin/env to invoke yasm/ld from PATH. With this I can build the compiler on NixOS. The way this would work in libc is you would call execvpe instead of execve, which resolve the program to one that is found in PATH. I expect the final solution for this would be to add functionality in std to find a program in PATH. Once there's a way to access the environment variables that can be implemented.

    opened by marler8997 2
  • Hello

    Hello

    First of all, i wanna thank you for this repo :) This is not a issue, but a question, since obviously you have more experience than me, and im just trying to find something.... I was searching for more repos like this, a kind of "programming language", but i literally found nothing, if you had to know some code that could help i will be thankful. ! I basically would love to have it in c/cpp, but anything can work !

    Thanks for your time, and hope you reply soon :)

    opened by Mr-CYBERPAPER 1
  • use

    use "#!/usr/bin/env bash" instead of "!#/bin/bash"

    The "#!/usr/bin/env bash" shebang header is more flexible and works with more distributions. Using /usr/bin/env means bash will be selected based on PATH. This means different versions of bash can be used for each shell environment which is difficult when using a hardcoded globally share path like /bin/bash. This also makes it work on more distributions which don't use global shared paths like NixOS.

    opened by marler8997 1
  • [Idea] `with` blocks instead of `defer`

    [Idea] `with` blocks instead of `defer`

    Maybe instead of using defer statements we can use with blocks:

    struct A{
        a: i32,
    }
    
    fn new_a(): A*{
        ...
    }
    
    method A::close(){
        ...
    }
    
    fn main(){
        with let foo: A* = new_a(){
            ...
        }
    }
    

    Which essentially means:

    struct A{
        a: i32,
    }
    
    fn new_a(): A*{
        ...
    }
    
    method A::close(){
        ...
    }
    
    fn main(){
        let foo: A* = new_a();
        ...
        foo::close();
    }
    
    opened by Weltspear 6
  • Can't compile cup program which has a function which returns a struct

    Can't compile cup program which has a function which returns a struct

    I tried to compile the following program:

    struct A{
    	a: int;
    	b: int;
    	c: int;
    }
    
    fn a(): A{
    	let a_: A;
    	a_.a = 1;
    	a_.b = 2;
    	a_.c = 2;
    	return a_;
    }
    
    
    fn main(){
    
    }
    
    

    Compiler tells me:

    A
    compiler/codegen.cup:66:9: Unsupported type size
    
    opened by Weltspear 16
Owner
Mustafa Quraish
I like almost anything to do with computers
Mustafa Quraish
A tool that, like, screams at you when you say like

Dislike Do you, like,... dislike constantly saying "like" as much as I do? Then, like,... you've come the right place! This tool is like EXACTLY what

ElKowar 27 Jun 27, 2022
A simple programming language for everyone.

Slang A simple programming language for everyone, made with Rust. State In very early stages. Plan is to create a byte-code compiler and make that exe

Slang, Inc. 11 Jul 1, 2022
Simple programming language that speaks the ones you already know!

Simple programming language that speaks the ones you already know!

LyonSyonII 2 Feb 12, 2022
A simple interpreter written in Rust programming language.

Interpreter in Rust A simple interpreter written in Rust programming language. Getting Started These instructions will get you a copy of the project u

Ismail Mosleh 5 Feb 17, 2023
Compiler from a lisp-like language to mlog

slimlog slimlog compiles a lisp-like language to mlog Architecture slimlog is divided into three distinct parts Parser Parses the source file Compiler

The Potato Chronicler 6 May 7, 2022
A programming language. Better mantra pending.

Dusk Dusk is a programming language I've been working on on and off for the past while now. It's still very much in its infancy (... a quick look thro

Kaylynn Morgan 14 Oct 24, 2022
Ruxnasm is an assembler for Uxntal — a programming language for the Uxn stack-machine by Hundred Rabbits

Ruxnasm is an assembler for Uxntal — a programming language for the Uxn stack-machine by Hundred Rabbits. Ruxnasm strives to be an alternative to Uxnasm, featuring more user-friendly error reporting, warnings, and helpful hints, reminiscent of those seen in modern compilers for languages such as Rust or Elm.

Karol Belina 44 Oct 4, 2022
Frame is a markdown language for creating state machines (automata) in 7 programming languages as well as generating UML documentation.

Frame Language Transpiler v0.5.1 Hi! So very glad you are interested in Frame. Frame system design markdown language for software architects and engin

Mark Truluck 35 Dec 31, 2022
beat saber is a strongly typed, self-documenting and highly performant programming language

beatsaber beat saber is a strongly typed, self-documenting and highly performant programming language. With beat saber we aimed to create a language t

Untitled 4 Jan 17, 2022
Analogous, indented syntax for the Rust programming language.

Note: After experimenting with this in the wild, I have found representing keywords as symbols to be far less readable in large codebases. Additionall

null 42 Oct 2, 2021
A cell-based esoteric programming language

Tape A cell-based esoteric programming language Tape is a cell-based, brainfuck-like programming language that has a readable syntax and a non-wasted

Gabriel Pacheco 2 Feb 23, 2022
Programming language from down under, inspired by this Reddit post.

aussie++ Programming language from down under, inspired by this Reddit post. View live demo here. Special thanks to MarkWhyBird, louis100, and others

Zack Radisic 562 Dec 27, 2022
Programming Language Inspired by Brainfuck

Brainsuck Brainfuck but not really... like... a better version of it. Installation Requirements: Rust version 1.50 or higher Linux curl https://raw.gi

Derin Önder Eren 27 Nov 18, 2022
A Star Wars inspired by programming language

The Force The Force is a gateway to abilities many believe are unnatural... Getting Started Install Rust. We also provide a Dev Container if you would

Matthew Booe 14 Dec 21, 2022
An incremental programming language

Differential Datalog (DDlog) DDlog is a programming language for incremental computation. It is well suited for writing programs that continuously upd

VMware 1.2k Dec 28, 2022
🤯 A brainf*ck-style programming language, but readable

?? Brainease Brainease is a brainf*ck-style programming language, but readable. $ cargo install brainease # brainease -f examples/hello.bz save 'H

Arthur Fiorette 11 Sep 30, 2022
A fast & light weight Discord Client made with love using the Rust programming language.

LemonCord A fast & light-weight Discord Client written in Rust using the wry crate. Features Fast, light-weight, easy to use. 100% Open sourced. No su

Lemon Rose 5 Jan 30, 2023
Compiler & Interpreter for the (rather new and very experimental) Y programming language.

Y Lang Why would anyone build a new (and rather experimental) language with no real world use case. Design Y (pronounced as why) is based on the idea

Louis Meyer 8 Mar 5, 2023
The official programming language of the Hasso Plattner Institute.

Die HPI Programmiersprache Die offizielle Programmiersprache des HPI. Anmerkung: Dieses Projekt soll niemanden beleidigen oder bloßstellen, alles bitt

null 7 Oct 22, 2023