Menu

Tree [337f34] master /
 History

HTTPS access


File Date Author Commit
 analyzer.py 2016-12-31 Elias Pschernig Elias Pschernig [ad86c2] make auto work for parameters and local variables
 cout.py 2017-02-12 Elias Pschernig Elias Pschernig [337f34] still keep static imports above static forward ...
 ctypesout.py 2012-06-05 Debian User Debian User [94ecd9] different things, don't feel like untangling
 dout.py 2015-09-21 Elias Pschernig Elias Pschernig [2463db] include types in documentation generator
 eout.py 2017-02-12 Elias Pschernig Elias Pschernig [64e5ce] some improved error checks
 helper.py 2016-12-31 Elias Pschernig Elias Pschernig [ad86c2] make auto work for parameters and local variables
 join.py 2016-12-30 Elias Pschernig Elias Pschernig [6e3d84] be more intelligent when joining files
 parser.py 2017-02-12 Elias Pschernig Elias Pschernig [64e5ce] some improved error checks
 readme.md 2017-01-11 elias-pschernig elias-pschernig [139943] Update readme.md
 scramble.py 2016-12-31 Elias Pschernig Elias Pschernig [ad86c2] make auto work for parameters and local variables
 sout.py 2015-07-13 Elias Pschernig Elias Pschernig [6880f3] several things
 terminal.py 2015-09-21 Elias Pschernig Elias Pschernig [2463db] include types in documentation generator
 test.py 2017-02-12 Elias Pschernig Elias Pschernig [94e8a9] place static for declarations later
 unscramble.py 2016-04-17 Elias Pschernig Elias Pschernig [959ae6] improve unscramble ever so slightly

Read Me

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.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.