CS 433 - The #YOCO Report

#YOCO (You Only Code Once) is a simple procedural programming language used as the input language for our compiler in CS 433, Fall 2014. #YOCO variables start with '#', the assignment operator is '@', statements are terminated with '!', and 'like' is used for equality. The file extension for #YOCO programs is ".yoco". #YOCO programs are best shared using twitter, though they might need to be split into multiple tweets.

#YOCO supports two basic types: int and yono (Booleans with values yo and no), as well as arrays of ints and yonos. The language also supports recursion and nested scopes. Parameters can be passed by value and by reference. Input and output of integers and characters is supported. Not in the language are records, pointers, floats, and strings. #YOCO's syntax is based on suggestions by the students in the class. The language is derived from subsets of C, C#, and Python, with syntactic quirks inspired by twitter (for instance, return is "retweet".)

A formal grammar for #YOCO.

Language details:

  1. #YOCO's keywords are: int yono yo no global retweet if else while end or and not like ref

  2. #YOCO's operators and reserved characters are:
    # required prefix for all variables
    < <= > >=     comparison operators (equality is 'like' and inequality is 'not like')
    + - * / % arithmetic operators
    @ assignment operator
    : follows 'if', 'else', and 'while' statements, as well as function definitions (like in Python) and starts a block, while 'end' ends a block
    ! terminates statements
    ( ) [ ] expression grouping / array subscript (same as in Java)
    .. defines subscript range in array declaration
    , separates parameters and variables

  3. Comments are the same as in C++ and Java: single-line comments start with "//" and extend to the end of the line. Multi-line comments start with "/*" and end with "*/"; they cannot be nested.

  4. The language is case-sensitive, e.g., "x" and "X" are different names, and all keywords must be lower case.

  5. Identifiers must start with a letter and can contain letters, numbers, underscores, and question marks.

  6. Variables are declared like in Java / C, e.g., "int #i, #j! yono #b!".

  7. Array declarations include a subscript range after the type name: "int[0..7] #x! yono[-2..2] #z!". The range needs to be given as two integer constants.

  8. Basic variables can be initialized as they are declared ("int #x = 2 * #y!), but arrays cannot.

  9. Variable declarations and statements can be interleaved (like in C++ and Java).

  10. Functions are declared like in C / Java; procedures (i.e., void functions) are simply declared without a type. Function/procedure headers are followed by ":" like in Python, but (unlike Python) white space / indentation is ignored. The body of a function is terminated "end". Like in Java and unlike in C, functions/procedures can be defined in any order.

  11. The return statement is "retweet", with an optional argument. The argument is required in functions and not allowed in procedures.

  12. Global variables can be declared before functions and procedures, but they cannot be initialized. They need to be prefixed with the keyword "global".

  13. Integer and boolean parameters can be passed by value (e.g., "int #a") or by reference (e.g., "ref int #a"). Array parameters are automatically passed by reference, without specifying the bounds (e.g. "int[] #a"). Each parameter must be listed with a type (like in C / Java), e.g., "gcd(int #a, int #b)".

  14. "if" statements have optional "else if" and "else" parts. Both "if" and "while" statements are terminated by "end". Like in Python, conditions of "if", "else if", and "while" statements (and "else") are followed by ":" and don't need to be surrounded by parentheses.

  15. Execution starts with the parameterless procedure "YOCO()" (like "main" in C / Java). Command-line arguments are not supported.

  16. The functions int get() and int getc() are provided for input; the procedures put(int n) and putc(int c) are provided for output. The 'c' versions read/print characters, the others integers.

  17. Character constants are supported as 'c', where c is any character except a newline, a backslash, or a single quote. These three special characters are represented with '\n', '\\', and '\''. A character constant is simply an integer (the corresponding ASCII code) - that is, there is no type "char". Character constants come in handy in conjunction with the putc procedure.

Here are some sample #YOCO programs:

// gcd.yoco
// Asks user for two integers and prints their GCD

int gcd(int #a, int #b): // compute the GCD of a, b recursively
    if #b > #a:
        retweet gcd(#b, #a)!
    else if #b like 0:
        retweet #a! 
        retweet gcd(#b, #a % #b)!

YOCO():                // main program
    int #x @ get()!   // get first number from user
    int #y @ get()!   // get second number from user
    putc('G')! putc('C')! putc('D')! putc('=')!
    put(gcd(#x, #y))! putc('\n')!


/* reverse.yoco
 reverses string entered by the user
 (this is a multi-line comment)

global int #newline!  // global variable

    int #c @ getc()!        // read first character
    if #c not like #newline:
        rev()!              // reverse rest of string
    putc(#c)!               // print first character

    #newline @ '\n'!


// bubble.yoco
// bubble sort of 5 integers

swap(ref int #a, ref int #b): // swaps #a and #b, which are passed by reference
    int #tmp @ #a!
    #a @ #b!
    #b @ #tmp!

bubble(int[] #X, int #lo, int #hi): // sorts #X[#lo..#hi] using bubble sort
    while #hi > #lo:
        int #j @ #lo!
        yono #changed? @ no!
        while #j < #hi:
            if #X[#j] > #X[#j+1]:
                swap(#X[#j], #X[#j+1])!
                #changed? @ yo!
            #j @ #j + 1!
        if not #changed?: 
        #hi @ #hi - 1!

YOCO():         // main program
    int[1..5] #A!
    #A[1] @  6!
    #A[2] @ -2!
    #A[3] @ 44!
    #A[4] @  3!
    #A[5] @  5!
    bubble(#A, 1, 5)!
    put(#A[1])! putc(' ')!
    put(#A[2])! putc(' ')!
    put(#A[3])! putc(' ')!
    put(#A[4])! putc(' ')!
    put(#A[5])! putc('\n')!