Subscribe for updates!

Pyxie


Changelog
Open Source
Credits
Dev Status
Overview
Language Spec
Language Status
Project Status
Downloads, Links, etc
Arduino Profile

Pyxie -- A Little Python to C++ Compiler

Latest Release: 0.1.25 (3/Feb/2018)

What job does / will this do?

The aim of this project is to allow adults and children to write code in a familiar high level language that can then be compiled to run on an arbitrary embedded system - that is devices with very low power CPUs and very little memory. (ie devices too small to host a python interpreter/runtime)

It's pre-alpha at the moment. However, as of Sept 2016, it's beginning to be usable for compiling very simple python programs that can run directly on an arduino, starting with those that can control servos. This means small python powered robots :)

It will be useful in supporting things like the The Scout Association's "Digital Maker" badge. That's a fair way off though.

Show me something you CAN compile

Currently it can compile very very simple types of python program that looks like this into an equivalent (simple) C++ program.

Source:
age = 10
new_age = 10 +1
new_age_too = age + 1
new_age_three = age + new_age_too
foo = "Hello"
bar = "World"
foobar = foo + bar

print(10-1-2,7)
print(1+2*3*4-5/7,25)
print(age, new_age, new_age_too)
print(foo, bar, foobar)

countdown = 2147483647
print("COUNTING DOWN")
while countdown:
    countdown = countdown - 1

print("BLASTOFF")
Generated:
#include <iostream>
#include <string>

using namespace std;

int main(int argc, char *argv[])
{
    int age;
    string bar;
    int countdown;
    string foo;
    string foobar;
    int new_age;
    int new_age_three;
    int new_age_too;

    age = 10;
    new_age = (10+1);
    new_age_too = (age+1);
    new_age_three = (age+new_age_too);
    foo = "Hello";
    bar = "World";
    foobar = (foo+bar);
    cout << ((10-1)-2) << " " << 7 << endl;
    cout << ((1+((2*3)*4))-(5/7)) << " " << 25 << endl;
    cout << age << " " << new_age << " " << new_age_too << endl;
    cout << foo << " " << bar << " " << foobar << endl;
    countdown = 2147483647;
    cout << "COUNTING DOWN" << endl;
    while(countdown) {
        countdown = (countdown-1);
    };
    cout << "BLASTOFF" << endl;
    return 0;
}

Basic Arduino Example

Source: arduino-for-blink.pyxie
    led = 13;

    pinMode(led, OUTPUT);

    while True:
        for i in range(6):
            digitalWrite(led, HIGH)
            delay(200)
            digitalWrite(led, LOW)
            delay(200)
        delay(1000)
Generated: arduino-for-blink.ino
#include "iterators.cpp"
 
void setup()
{
    int i;
    int led;
    range range_iter_1;
    led = 13;
    pinMode(led, OUTPUT);
    while(true) {
        range_iter_1 = range(6);
        while (true) {
            i = range_iter_1.next();
            if (range_iter_1.completed())
                break;
             digitalWrite(led, HIGH);
             delay(200);
             digitalWrite(led, LOW);
             delay(200);
        };
        delay(1000);
    };
}
 
void loop()
{
}

Example Arduino Program using Servos

Source: servo-test-target.pyxie

    #include <Servo.h>

    myservo = Servo()
    pos = 0
    pin=11

    myservo.attach(pin)
    while True:
        for pos in range(180):
            myservo.write(pos)
            delay(15)

        for pos in range(180):
            myservo.write(179-pos)
            delay(15)
Generated: servo-test-target.ino
#include <Servo.h>
 
#include "iterators.cpp"
 
void setup() {
    Servo myservo;
    int pin;
    int pos;
    range range_iter_1;
    range range_iter_2;

    pos = 0;
    pin = 11;
    (myservo).attach(pin);
    while (true) {

        range_iter_1 = range(180);
        while (true) {
            pos = range_iter_1.next();
            if (range_iter_1.completed())
                break;


            (myservo).write(pos);
            delay(15);          // Itself uses pos
        }
        ;

        range_iter_2 = range(180);
        while (true) {
            pos = range_iter_2.next();
            if (range_iter_2.completed())
                break;


            (myservo).write((179 - pos));
            delay(15);          // Itself uses pos
        }
        ;
    };
}
 
void loop() {
}

Analog, serial demo Arduino program:

Source: analog/analog-serial.pyxie
    analogInPin = A0
    analogOutPin = 9
    sensorValue = 0
    outputValue = 0
    Serial.begin(9600)
    randomTest = 0
    randomSeed(analogRead(0))

    while True:
        sensorValue = analogRead(analogInPin)
        sensorValue = constrain(sensorValue, 10, 150);
        outputValue = map(sensorValue, 0, 1023, 0, 255)
        randomTest = random(300)
        analogWrite(analogOutPin, outputValue)
        Serial.print(millis())
        Serial.print(" : ")
        Serial.print("sensor:- ")
        Serial.print(sensorValue)
        Serial.print(" output:- ")
        Serial.print(outputValue)
        Serial.print(" random:- ")
        Serial.print(randomTest)
        Serial.println("--------")
        delay(2)
Generated: analog-serial.ino
#include "iterators.cpp"
 
#include "iterators.cpp"
 
void setup() {
    int analogInPin;
    int analogOutPin;
    int outputValue;
    int randomTest;
    int sensorValue;

    analogInPin = A0;
    analogOutPin = 9;
    sensorValue = 0;
    outputValue = 0;
    (Serial).begin(9600);
    randomTest = 0;
    randomSeed(analogRead(0));
    while (true) {
        sensorValue = analogRead(analogInPin);
        sensorValue = constrain(sensorValue, 10, 150);
        outputValue = map(sensorValue, 0, 1023, 0, 255);
        randomTest = random(300);
        analogWrite(analogOutPin, outputValue);
        (Serial).print(millis());
        (Serial).print(" : ");
        (Serial).print("sensor:- ");
        (Serial).print(sensorValue);
        (Serial).print(" output:- ");
        (Serial).print(outputValue);
        (Serial).print(" random:- ");
        (Serial).print(randomTest);
        (Serial).println("--------");
        delay(2);
    };
}
 
void loop() {
}

What does it do?

Currently:

Python structural things it supports:

This is close to allowing actually useful programs now.

It's a starting point, not the end point. For that, take a look at the language spec.

Pyxie is intended to be a simple Python to C++ compiler, with a target of compiling python code such that it can run on a microcontroller - like Arduino, MSP430 or ARM mbed type devices.

The name is a play on words. Specifically, Python to C++ - can be py2cc or pycc. If you try pronouncing "pycc" it can be "pic", "py cc" or pyc-c". The final one leads to Pixie.

This is unlikely to ever be a completely general python to C++ compiler - if you're after than look at Shed Skin, or things like Cython, Pyrex, and PyPy. (in terms of diminishing similarity) The difference this project has from those is that this project assumes a very small target device. Something along the lines of an Atmega 8A, Atmega 328 or more capable.

In the past I've written a test driven compiler suite, so I'll be following the same approach here. It did consider actually making Pyxie use that as a frontend, but for the moment, I'd like python compatibility.

Why not micropython? Micropython is ace . If your device is large enough to support the micropython runtime, use it! The aim of this is on the really small microcontrollers- the ones too small to even support micropython - like an MSP430, or an Atmega 8A or similarly tiny MCU.

In the past I've written a test driven compiler suite, so I'll be following the same approach here. It did consider actually making Pyxie use that as a frontend, but for the moment, I'd like python compatibility.

Status Overview

For the impatient: this probably does NOT do what you want, yet.

High level view of support:

This means we can almost start writing useful programs, but in particular can start creating simplistic benchmarks for measuring run speed. It IS getting there however, and feedback, usecases, devices very welcome.

Influences

Many moons ago, I made a generic language parser which I called SWP (semantic whitespace parser), or Gloop.

It was an experiment to see if you could write a parser that had no keywords, or similar, in a completely test driven fashion. ie a bit like a parser for a Lisp like language that would look like python or ruby. It turns out that you can and there's lots of interesting things that arise if you do. (Best seen in the slideshare link)

Which version of Python?

It's not a complete subset of any particular python, but it's based around the intersection points in python 2 and 3. It will be, by definition, a non-dynamic subset - at least at first.

These are all a WIP, but becoming more solid.

Why write this?

Personally, having built something simpler in the past, I know I'd find it useful. (I use python rather than C++ often because I can write more quicker with the former). Also, I work with kids in my spare time, and it opens up options there.

I've written something like this for work last year, but that was much more limited and restricted in both aspiration and implementation. This rewrite is something I've done on my own time, with my own tools, from scratch, which allows me to share this with others.

Major changes:

That potentially allows other things, like creation of visual representations of programs from code as well.

Is this part of any larger project?

No. It could be used by others, but it's got a definite goal - to allow the use of a "little" python to program devices which are too small to host a python runtime.

If anything, it's a continuation of the personal itch around SWP (mentioned above) from about 10 years ago. Unlike that though, it's much, much better structured.

One thing that may happen though is the ability to take python classes and derive iotoy device implementations/interfaces directly. (since iotoy was inspired heavily by python introspection) That's quite some time off.

Release History

Release History:



Updated: October 2016
Help, Contacts & Downloads
Copyright © 2016 Michael Sparks Open Source