Skip to content

allefant/scramble

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 

Repository files navigation

Scramble

About

Scramble is a C preprocessor which allows to write C code which looks a bit like Python code with a full Python3 environment available for meta programming. That is, no semantics at all are changed - when using Scramble you still write C code. But it has a syntax more similar to Python.

Similar (and better) projects:

Example

Scramble is used like this:

scramble.py -i input.py -c output.c -h output.h -n name

For example, if you have a file main.py, then you could run:

scramble.py -i src/main.py -c build/c/main.c -h build/h/main.h -n main

And if your src/main.py would look like to the left, the resulting files would look like to the right:

src/main.py

import stdio, string, math

def main(int argc, char **argv) -> int:
    if argc == 2:
        printf("%f\n", sin(strtod(argv[1]))
        return 0
    else:
        fprintf(stderr, "Need exactly one argument!\n")
        return 1

build/c/main.c

#include "main.h"

int main(int argc, char **argv)
{
    if (argc == 2) {
        printf("%f\n", sin(strtod(argv[1]));
        return 0;
    }
    else {
        fprintf(stderr, "Need exactly one argument!\n");
        return 1;
    }
}

build/h/main.h

#ifndef _MAIN_

#include "stdio.h"
#include "string.h"
#include "math.h"

extern int main(int argc, char **argv);

#endif

Keywords

All C, C++ and Python keywords basically are also Scramble keywords. The following control flow constructs are used by scramble: while, switch...case, do...while, for X while Y with Z [for (X; Y; Z) in C], for...in, if...elif...else, label [: in C], goto.

And these declarations: class [struct in C], def, enum, global, import, macro [#define in C], static, struct, typedef, union.

These Python operators are used instead of the C++ ones: and [&& in C], max, min, not [! in C], or [|| in C].

And there's a few new constants: True, False, None.

Features

In general, here is what scramble will do:

  • No more ; required.

  • : and indentation instead of { and }.

  • No ( and ) for builtin C keywords like if. For example:

    if x == 2:
        x = 3
        y = 3
    
    translates to
    if (x == 2) {
        x = 3;
        y = 2;
    }
    
  • Use elif instead of else if, like in python.

  • Use and, or and not inside conditionals, like in python.

  • Functions are declared with def, and parameter types can be grouped. For example:

    def f1():
        pass
    
    def f2(int x, y, z):
        pass
    
    def f3 -> int:
        pass
    
    translates to
    void f1(void) {
    }
    
    void f2(int x, int y, int z) {
    }
    
    int f3(void) {
    }
    
  • Headers are generated automatically. This works by outputting a declaration for each function or global variable which is not declared static. Similarly, struct/union/enum declarations are written into the header unless declared static, and a type is automatically defined for them. For example:

    test.py

    class A:
        int x
    
    class B:
        A *a
    
    static class C:
        B *b
    
    static def a_new() -> A*:
        A *self = calloc(1, sizeof *self)
        return self
    
    def b_new() -> B*:
        B *self = calloc(1, sizeof *self)
        self->a = a_new()
        return self
    
    translates to

    test.c

    #include "test.h"
    
    typedef struct C C;
    
    struct C
    {
        B *b;
    };
    
    static A *a_new(void)
    {
        A *self = calloc(1, sizeof *self);
        return self;
    }
    
    B *b_new(void)
    {
        B *self = calloc(1, sizeof *self);
        self->a = a_new();
        return self;
    }
    

    and

    test.h

    #ifndef _TEST_
    
    typedef struct A A;
    typedef struct B B;
    
    struct A
    {
        int x;
    };
    
    struct B
    {
        A *a;
    };
    
    B *a_new(void);
    
    #endif
    
  • Comments are started with #.

  • Include files are included with import. For example:

    import test, global stdio
    
    translates to
    #include "test.h"
    #include <stdio.h>
    
  • Meta programming using full Python. This is possibly the single most useful feature - at compile time you have the full Python interpreter at your disposal to create any code you want.

    ***scramble
    for x in ["A", "B", "C"]:
        parse("char def function" + x + "(): return '" + x + "'")
    ***
    
    translates to
    char functionA(void) {
        return 'A';
    }
    
    char functionB(void) {
        return 'B';
    }
    
    char functionC(void) {
        return 'C';
    }
    
  • Triple quoted strings, useful for multi-line string constants.

  • Support for auto declarations (type is inferred)

  • In many cases you can use . instead of -> (if the type inference sees a pointer left of the . a -> is output instead)

  • Extended for-loop syntax, for example:

        MyArray *arr
        for MyElem *x in arr:
        handle(x)
    
    translates to
    MyArrayIterator __iter__ = MyArrayIterator_first(arr);
    for (MyElem *x = MyArrayIterator_item(arr, &__iter__);
            MyArrayIterator_next(arr, &__iter__);
            x = MyArrayIterator_item(arr, &__iter__)) {
        handle(x);
    }
    
  • Docstrings can be used to automatically generate documentation. Strings at the beginning of a function are ignored, but can optionally be output to a separate file, associated with the function they are defined in. This can then be used to translate into different documentation formats.

More stuff (might change?)

  • None, min, max, True, False keywords. For now min and max are macros for the ternary operator - with the usual problem of evaluating the argument twice.
  • As the hash sign starts a comment, *** can be used to insert C preprocessor commands.
  • Instead of #define, macro and static macro can be used to place a #define either into the .h or .c file.
  • Since the : is used up by Python syntax, labels are marked with the label keyword instead of :. Bitfields use the keyword with. The colon in the C tertiary operator works for now until I implemnt the if-else construct.

About

Python to C compiler

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages