From Céupédia
Jump to: navigation, search


Please refer to

Céu is a reactive language targeted at embedded systems and intended to offer a higher-level and safer alternative to C. Reactive programs are mostly guided by the environment, which issues input events into the program that must be promptly acknowledged.

Céu supports multiple lines of execution, known as trails, which are allowed to share variables in a safe and seamless way (e.g. no need for locks or semaphores). The synchronous concurrency model of Céu greatly diverges from conventional multithreading (e.g. pthreads) and the actor model (e.g. erlang): In Céu, trails execute synchronized in reaction to a single input event at a time, hence, it is impossible to have trails reacting to different events. The disciplined step-by-step execution in Céu enables a rigorous analysis that guarantees at compile time that programs are completely race free.

Céu integrates well with C, being possible to define and call C functions from within Céu programs.

Céu has a memory footprint of around 2Kb of ROM and 50b of RAM (on a 16bits platform).

Céu is free software.

For a gentle introduction about Céu, see the interactive tutorial.

See also the complete Syntax of Céu for further reference.

1 Lexical Rules

1.1 Keywords

Follows the list of reserved keywords in Céu:

   and         async       await       break       C           constant    deterministic
   do          else        else/if     emit        end         event
   finally     FOREVER     if          input       int         loop        nohold
   not         null        or          output      par         par/and     par/or
   pause/if    pure        return      s8          s16         s32         s64
   sizeof      then        var         void        with        u8          u16
   u32         u64

1.2 Identifiers

Céu uses identifiers to refer to external events, internal events, variables, C symbols, and types:

   ID      ::= <a-z, A-Z, 0-9, _> +
   ID_ext  ::= ID    /* all in uppercase, not beginning with a digit */
   ID_int  ::= ID    /* beginning with a lowercase letter            */
   ID_var  ::= ID    /* beginning with a lowercase letter            */
   ID_c    ::= ID    /* beginning with an underscore                 */
   ID_type ::= ( ID_c | void | int
              | s8 | s16 | s32 | s64
              | u8 | u16 | u32 | u64 ) (`*´ *)


   var int a;                    // `int´ is a type, `a´ is a variable
   await A;                      // `A´ is an external input event
   emit e;                       // `e´ is an internal event
   _printf("hello world!\n");    // `_printf´ is a C symbol

1.3 Literals

1.3.1 Integers

Céu supports integer values written in different bases and also as ASCII characters:

  • Decimals are written as is.
  • Octals are prefixed with 0.
  • Hexadecimals are prefixed with 0x.
  • ASCII characters and escape sequences are surrounded by apostrophes.


   // all following are equal to the decimal 127
   v = 127;
   v = 0777;
   v = 0x7F;
  // newline ASCII character = decimal 10
   c = '\n';

1.3.2 Strings

A sequence of characters surrounded by `"´ are converted into a null-terminated string, just like in C:


   _printf("Hello World!\n");


Céu provides C-style comments.

Single-line comments begin with `//´ and run to end of the line.

Multi-line comments use `/*´ and `*/´ as delimiters. Multi-line comments can be nested by using a different number of `*´ as delimiters.


   var int a;    // this is a single-line comment
   /** comments a block that contains comments
   var int a;
   /* this is a nested multi-line comment
   a = 1;

2 Types

Céu is statically typed, requiring all variables and events to be declared before they are used.


   var u8 v;             /* `v´ is of 8-bit unsigned integer type */
   var _message_t msg;   /* `msg´ is of external C type `message_t´ */
   var _char* buf;       /* `buf´ is a pointer to external C type `char´ */

2.1 Native types

Céu supports the following native types:

   void               /* void type for signal-only events */
   int                /* platform dependent integer */
   s8       u8        /* signed and unsigned  8-bit integer */
   s16      u16       /* signed and unsigned 16-bit integer */
   s32      u32       /* signed and unsigned 32-bit integer */
   s64      u64       /* signed and unsigned 64-bit integer */

2.2 C (external) types

Types defined externally in C can be prefixed by `_´ to be used in Céu programs.

The size of an external type must be explicitly declared.


   C _char = 1;      /* declares the external C type `_char´ of 1 byte */

2.3 Pointers

Any type, being it native or external, can be postfixed with `*´ to become a pointer to that type.

3 Statements

3.1 Blocks

A block is a sequence of statements separated by semicolons (`;´):

   Block ::= { Stmt `;´ }

Note: statements terminated with the end keyword do not require a terminating semicolon.

A block creates a new scope for variables, which are only visible for statements inside the block.

Compound statements (e.g. if-then-else) create new blocks and can be nested for an arbitrary level.

3.2 Declarations

3.2.1 Variables

The syntax for the definition of variables in Céu is as follows:

   Dcl_var ::= var ID_type (`[´ NUM `]´)? ID_var (`=´ SetExp)? ( `,´ ID_var (`=´ SetExp)? )*

A variable must have an associated type and can be optionally initialized.

Variables are only visible inside the block they are defined.

Céu supports one-dimensional vectors, which are declared by suffixing the variable type (instead of its name) with the vector length surrounded by `[´ and `]´. The first index of a vector is zero.

Note: currently, Céu has no syntax for initializing vectors.


   var int a=0, b=3;   /* declares and initializes integer variables `a´ and `b´ */
   var int[2] v;       /* declares a vector `v´ of size 2 */

3.2.2 Events External events

External events are used as interfaces between programs and devices from the real world.

External input events are used for interacting with input devices, such as sensors, switches, etc.

Being reactively guided, programs in Céu have input events as their sole entry points through await statements.

The declaration of an input event is as follows:

   Dcl_ext ::= input ID_type ID_ext (`,´ ID_ext)*

External output events are used for interacting with output devices, such as leds, motors, etc.

The declaration of an output event is as follows:

   Dcl_ext ::= output ID_type ID_ext (`,´ ID_ext)*

An external event is either of type input or output, never being both at the same time. For devices that perform input and output (e.g. radio transceivers), the underlying platform must provide different events for each functionality.

The type on the declarations refer to the value the declared event transports between the environment and the application (and vice-versa).

Note: void is a valid type for signal-only events.

The visibility of external events is always global, regardless of the block they are declared.


   input void MyEvent;    // `MyEvent´ is an input event that carry no values (i.e., it is a signal-only event)
   output int  A,B,C;     // `A´, `B´, and `C´ are integer output events

The availability of external events depends on the platform in use. Therefore, external declarations just enable pre-existing events to be used in a program.

Refer to the Section #Environment for information about interfacing with external events in the platform level. Internal events

Internal events are used as a communication mechanism among trails through the await and emit statements.

The declaration of an internal event is as follows:

   Dcl_int ::= event ID_type ID_int (`,´ ID_int)*

In contrast with external events, an input event is always used for input and output at the same time.

Internal events cannot be of a vector type.

Note: void is a valid type for signal-only internal events.

3.2.3 C (external)

Any existing type, variable, or function in C can be predeclared to be available for use in Céu programs:

   Dcl_c   ::= C (pure|constant|nohold)? C_list
   C_list  ::= (C_type|C_func|C_var) (`,´ (C_type|C_func|C_var))*
   C_type  ::= ID_c `=´ NUM
   C_func  ::= ID_c `(´ `)´
   C_var   ::= ID_c

A declaration is a list of C symbols, all prefixed with `_´, referring to available static globals in the underlying C platform.

A type must include its size in bytes. Functions and variables are distinguished by the `()´ that follows function declarations.

After being declared, the symbols can be used in the program (keeping the prefix `_´).

An "opaque type" can be declared as having zero bytes. An opaque type is never instantiated, but always used as a pointer to be manipulated by external functions

Given that the Céu compiler has no information about external symbols, by default, C functions are considered to be impure (i.e. performs side-effects), and C variables to point to any memory location.

For this reason, concurrent accesses to external symbols are always considered non-deterministic.

To change the default behavior, a C declaration may be prefixed with an annotation:

  • constant states that the declared variables are actually constants (e.g. a #define).
  • pure states that the declared functions have no side effects.
  • nohold states that the declared functions do not hold references to pointers passed as parameters.

Annotations are discussed in more depth in sections do-finally-end and TODO(determinism).


   C constant _NULL;                  /* `_NULL´ is a constant */
   C _char=1, _FILE=0;                /* `_char´ is a 1-byte type, while `_FILE´ is "opaque" */
   C pure     _abs(), _pow();         /* `_abs´ and `_pow´ are pure functions */
   C nohold   _fprintf(), _sprintf(); /* these functions receive pointers but do not hold references to them */

Céu also supports C blocks to define new global types, variables, and functions using the C syntax:

   C_block ::= C do <code_with_C_syntax> end


   C _assert(), _inc();
   C do
       #include <assert.h>
       int inc (int i) {
           return i+1;
   _assert(_inc(0) == 1);

If the code in C contains the terminating end keyword of Céu, the C block must be delimited with a custom comment to avoid confusing the parser:

   C do
       /*** c code ***/
       char str = "This `end´ confuses the parser";
       /*** c code ***/

3.2.4 Deterministic annotations

A C function or variable (either from Céu or C) may be declared as deterministic with a set of other functions or variables:

   Dcl_det ::= deterministic ID with ID (`,´ ID)*


   C _p, _f1(), _f2();
   deterministic _f1 with _f2;
   var int* p;
   deterministic p with _p;
   par do
       _f1(...);    // `f1´ is deterministic with `f2´
       *p = 1;      // `p´  is deterministic with `_p´
       _f2(...);    // `f2´ is deterministic with `f1´
       *_p = 2;     // `_p´ is deterministic with `p´

Deterministic annotations are discussed in more depth in section TODO(determinism).

3.3 Assignments

Céu supports three kinds of assignments:

   Set ::= Exp `=´ ( Exp                /* simple assignment */
                   | <await_stmt>       /* await  assignment */
                   | <block_stmt> )     /* block  assignment */

The expression on the left side must be assignable.

3.3.1 Simple assignment

The simpler form of assignment uses expressions as values.


   var int a,b;
   a = b + 1;

3.3.2 Await assignment

Céu also supports assignments from await statements, as the Section #Await statements shows.

3.3.3 Block assignment

A whole block can be used as an assignment value by returning from it.


  // assigns 1 to the variable `a´
  var int a =
          return 1;

Every possible path inside the block must reach a return statement whose expression becomes the final value of the assignment.

The following statements can be used in block assignments: if-then-else, loop, par, do-finally-end, and async. return

A return statement is used to escape the deepest block being assigned to a variable. The return value is then assigned to the respective variable.


   a = loop do              // a=1, when `cond´ is satisfied
           await cond;
           if cond then
               return 1;    // `loop´ is the deepest assignment block

Every program in Céu contains an implicit do-end surrounding it, which assigns to a special integer variable $ret holding the return value for the program.

Therefore, a program such as

   return 1;

should read as

   var int $ret =
           return 1;

3.4 C calls

Céu has no support for function definitions, but functions defined in C can be called from Céu:

   Call ::=  Exp `(´ ExpList `)´

Expressions that evaluate to C functions can also be called.


   _printf("Hello World!\n");

3.5 Event manipulation

The fundamental concept in Céu, accounting for its reactive nature, is that of events.

Events are manipulated through the await and emit statements.

Waiting for an event halts the running trail until that event occurs.

The occurrence of an event is broadcast to all awaiting trails at the same time.

3.5.1 Await statements

The await statement halts the running trail forever or until the referred wall-clock time, input event, or internal event occurs.

   Await ::= (Exp `=´)? ( await (ID_ext|ID_int)
                        | await (WCLOCKK|WCLOCKE)
          |  await Forever


   await A;                  // awaits the input event `A´
   await a;                  // awaits the internal event `a´
   await 10min3s5ms100us;    // awaits the specified time
   await (t)ms;              // awaits the current value of the variable `t´ in milliseconds
   await Forever;            // awaits forever

An optional assignment captures the value the await evaluates to. Await event

For await statements referring to an event identifier, the running trail halts until that event occurs. When the event occurs, the statement resumes and evaluates to the triggered value.

   input int A;
   var int v = await A;       // `v´ is assigned the value of next occurrence of `A´ Await wall-clock

For await statements referring to wall-clock time (i.e., time measured in minutes, milliseconds, etc.), the running trail halts until the referred time elapses.

WCLOCKK and WCLOCKE are described as follows:

   WCLOCKK ::= (NUM h)? (NUM min)? (NUM s)? (NUM ms)? (NUM us)?
   WCLOCKE ::= `(´ Exp `)´ (h|min|s|ms|us)

A constant time (WCLOCKK) is expressed with a sequence of value/unit-of-time pairs. An expression time (WCLOCKE) is specified with an expression in parenthesis followed by a single unit of time.

After the referred time elapses, the await statement evaluates to the residual delta time (dt) (i.e. elapsed time minus requested time), measured in microseconds:

   var int dt = await 30ms;    // if 31ms elapses, then dt=1000

Note: dt is always greater than or equal to 0.

Refer to the Section #Environment for information about storage types for wall-clock time. Await Forever

The await Forever statement halts the running trail forever. It never evaluates to anything, and cannot be used in assignments.

3.5.2 Emit statements

The emit statement triggers the referred wall-clock time, external event, or internal event, awaking all trails waiting for that event (time).

   Emit ::= emit (ID_ext|ID_int) (`(´ Exp `)´)?
         |  emit (WCLOCKK|WCLOCKE) Emit event

  • External events:
For external events, the assignment expression is obligatory and represents the trigger value of the event (unless the event is of type void).
An emit on an output event returns immediately a status code of the action that runs asynchronously with the program.
Both the status code and that asynchronous actions are platform dependent. The status code is always of type int.
   output int Send;
   if not emit Send(1) then
      return 0;
Input events can only be emitted inside asyncs for the simulation of programs.
  • Internal events:
For internal events, the assignment expression is optional, and evaluates before the emit.
The two following are equivalent:
   emit a(4);


   a = 4;
   emit a();
The emit on an internal event suspends and resumes only after all the corresponding awaiting statements react to it. See also Section #Execution model for a precise description.
Internal emits have no return status and cannot be used as expressions. Emit time

The WCLOCKK and WCLOCKE parameters refer to wall-clock time, as described in Section #Await statements.

Just like for input events, wall-clock time can only be emitted inside asyncs.

3.6 Flow control

3.6.1 if–then–else

Céu provides an if–then–else statement as follows:

   If ::= if Exp then
          (else/if Exp then

The if–then–else statement executes the block following then if the condition expression evaluates to a non-zero value. Otherwise, it retries the process with the (optional) else/if alternatives. Finally, it they all fail, the block following the (optional) else is executed.

Note: the condition is not required to be surrounded by parenthesis.

3.6.2 loop

The loop statement continuously executes the block on its body until it reaches its specified limit or a break statement.

   Loop ::= loop (ID_var (`,´ Exp)?)? do Block end

The optional variable is automatically declared and initialized with zero. Its visibility is restricted to the loop body. The variable is read-only, but is automatically incremented after each iteration of the loop.

The optional limiting expression is evaluated once, before the loop starts. If no limiting expression is specified, the loop runs forever. break

The break statement escapes the innermost enclosing loop.


   loop do                   // loop 1
       loop do               // loop 2
           if cond then
               break;        // escapes loop 2
       if cond 2 then
           break;            // escapes loop 1

3.7 Parallel statements

The parallel statements par/and, par/or, and par split the running trail in multiple others. They differ only on how trails rejoin in the future.

See also Section #Execution model for a detailed description of parallel execution.

3.7.1 par/and

The par/and statement stands for parallel-and, meaning that the trails in parallel rejoin only after all of them terminate.

   ParAnd ::= par/and do

3.7.2 par/or

The par/or statement stands for parallel-or, meaning that the trails in parallel rejoin after any of them terminate.

   ParOr ::= par/or do

3.7.3 par

The par statement never rejoins and should be used when the trails in parallel are supposed to run forever (e.g. a loop without break).

   Par ::= par do

3.8 do-finally-end

A block can be explicitly created with a do-finally-end statement:

   Do ::= do Block (finally Block)? end

The optional finally block is executed even if the whole do-finally-end block is killed by a trail in parallel.

Note: the whole do-end defines a single block, i.e., variables defined in the do part are also visible to the finally part.

Consider the example that follows:

   par/or do
           _FILE* f = _fopen("/tmp/test.txt");
           await A;
           // use f
       await B;

Even if event B occurs before A, the opened file f is safely closed.

TODO: escape analysis / `:=´ assignments

3.9 pause/if


3.10 Asynchronous blocks

Asynchronous blocks (asyncs) permit that programs in Céu execute time consuming computations without interfering with reactions to input events (referred to as the synchronous side of applications). The syntax for asyncs is as follows:

   Async   ::= async ( `(´ VarList `)´ )? do Block end
   VarList ::= ID_var (`,´ ID_var)*

An async body can contain non-awaiting loops (tight loops), which are disallowed on the synchronous side to ensure that programs remain reactive.

The optional list of variables can be used to copy values from the current scope to be used inside the async body. Each identifier that appears on the list is automatically declared as new variable in the async body and initialized with the value of the variable with the same name in the current scope.

The following example executes a long computation inside an async in order to keep the program reactive. In a parallel trail, the program awaits one second to kill the computation if it takes too long:

  var int fat;
  var int Value;
  par/or do
      var int v = await Value;
      // calculates the factorial of v
      fat = async (v) do
          var int fat = 1;
          loop i, v do   // a tight loop
              // v varies from 0 to (v-1)
              fat = fat * (i+1);
          return fat;
      await 1s;          // watchdog to kill the async if it takes too long
      fat = 0;
  return fat;

The following restrictions are imposed to asyncs:

  • Asyncs only execute when there are no pending reactions to input events.
  • Asyncs are suspended whenever a new input event occurs.
  • Asyncs cannot use parallel compositions.
  • Asyncs cannot nest other asyncs.
  • Asyncs cannot await events.
  • Asyncs cannot emit internal events.
  • Asyncs do not share memory with the synchronous side.

A lower priority for asyncs is fundamental to ensure that input events are handled as fast as possible.

3.10.1 Simulation

As asyncs run detached from the synchronous side, they are allowed to trigger input events and the passage of time, providing a way to test programs in the own language:

  input int A;
  // tests a program with a simulation in parallel
  par do
      // original program
      var int v = await A;
      loop do
          await 10ms;
          _printf("v = %d\n", v);
          v = v + 1;
      // input simulation
      async do
          emit A(0);      // initial value for `v'
          emit 1s35ms;    // the loop executes 103 times
      return 0;
  // (try online!)

Whenever an async emits an event, it is suspeded due to its low priority compared to synchronous code. The example prints the message exactly 103 times.

4 Expressions

Besides constants, variables, C symbols, output emits, and function calls, Céu supports a wide range of expressions.

Most operators and expressions in Céu follow the same semantics of C.

Note: assignments are not expressions in Céu.

4.1 Arithmetic

The arithmetic operators of Céu are

   +      -      %      *      /      +      -

which correspond to addition, subtraction, modulo (remainder), multiplication, division, unary-plus, and unary-minus.

4.2 Relational

The relational operators of Céu are

   ==      !=      >      <      >=      <=

which correspond to equal-to, not-equal-to, greater-than, less-than, greater-than-or-equal-to, and less-than-or-equal-to.

Relational expressions evaluate to 1 (true) or 0 (false).

4.3 Logical

The logical operators of Céu are

   not      and      or

which correspond to not, and, or.

4.4 Bitwise

The bitwise operators of Céu are

   ~      &      |      ^      <<      >>

which correspond to not, and, or, xor, left-shift, and right-shift.

4.5 Vector indexing

Céu uses square brackets to index vectors:

   Index ::= Exp `[´ Exp `]´

The expression on the left side is expected to evaluate to a vector.

Vector indexes start at zero.

4.6 Pointers

The operator `*´ dereferences its pointer operand, while the operator `&´ returns a pointer to its operand:

   Deref ::= `*´ Exp
   Ref   ::= `&´ Exp

The operand to `&´ must be an assignable expression.

4.7 Structs

The operators `.´ and `:´ access the fields of structs.

   Dot   ::= Exp `.´ Exp
   Colon ::= Exp `:´ Exp

The operator `.´ expects a struct as its left operand, while the operator `:´ expects a reference to a struct.


   C do
       typedef struct {
           int v;
       } mystruct;
   var _mystruct s;
   var _mystruct* p = &s;
   s.v = 1;
   p:v = 0;

Note: structs must be declared in C, as Céu currently has no support for it.'

4.8 Type casting

Céu uses angle brackets for type casting:

  Cast ::= `<´ ID_type `>´

4.9 Sizeof

A sizeof expression returns the size of a type, in bytes:

   Sizeof ::= `sizeof´ `<´ ID_type `>´

The expression is evaluated at compile time.

Note: Céu has no support for evaluating the size of expressions.

4.10 Precedence

Céu follows the same precedence of C operators:

   /* lower to higer precedence */
   !=    ==
   <=    >=    <     >
   >>    <<
   +     -                // binary
   *     /     %
   not     &
   +     -                // unary
   <>                     // typecast
   ()    []    :    .     // call, index

4.11 Assignable expressions

An assignable expression (also known as an l-value) can be a variable, vector index, pointer dereference, or struct access. L-values are required in assignments and references.


   var int a;
   a = 1;
   var int[2] v;
   v[0] = 1;
   var int* p;
   *p = 1;
   var _mystruct s;
   s.v = 1;
   var _mystruct* ps;
   ps:v = 1;

5 Execution model


6 Environment

As a reactive language, Céu depends on an external environment (platform) to provide input and output events to programs. The environment is responsible for sensing the world and notifying Céu about changes.

The actual events vary from environment to environment, and an implementation may use a polling or interrupt-driven notification mechanism.

The Céu compiler generates a C output with hooks following a standard interface that the target platform should comply.

6.1 C API

The following sections specify the available mechanisms of interaction between the environment and the Céu runtime.

6.1.1 Functions

The following functions should be called by the environment to command the execution of Céu programs:

  • int ceu_go_init (int* ret)
Initializes and starts the program.
Should be called by the environment once, to start the Céu program.
If the program terminates, the function returns 1 and sets ret to the return value of the program.
Otherwise, the function returns 0.
  • int ceu_go_event (int* ret, int id, void* data)
Signals the occurrence of the given event to the Céu runtime.
The function receives the identifier of the input event (see constants) and a pointer to its data.
The program resumes on the trails awaiting the event, whose awaiting expressions return the received data.
The return procedure of the function behaves as ceu_go_init.
  • int ceu_go_async (int* ret, int* count)
Executes a suspended asynchronous block for a time slice.
The time slice is not specified, however the execution is interrupted when ceu_out_pending is true (see macros).
The return procedure of the function behaves as ceu_go_init, but also sets count to the number of suspended asynchronous blocks.
  • int ceu_go_wclock (int* ret, s32 dt)
Notifies the Céu runtime about the elapsed wall-clock time.
The function receives the elapsed time in microseconds as dt.
The program resumes on the trails whose wall-clock awaits have expired.
The return procedure of the function behaves as ceu_go_init.

Other functions:

  • int ceu_go_all ()
Combines ceu_go_init with an infinite loop that continuously calls ceu_go_async.
Expects that all events are generated from asynchronous blocks (see simulation).

6.1.2 Macros

The following macros can be optionally defined by the environment to customize the behavior of the Céu runtime:

  • ceu_out_pending()
Probes the environment for the existence of pending input events.
The expected return value is 1 (true) or 0 (false).
This macro is called from the Céu runtime to interrupt the execution of asynchronous blocks when the environment has a pending input event.
By default ceu_out_pending() translates to (1), meaning that asynchronous blocks execute the least possible time slice before giving control back to the environment.
  • ceu_out_wclock(us)
Notifies the environment that the next wall-clock await will expire in us microseconds.
This macro must be defined in interrupt-based platforms to remind the environment to call ceu_go_wclock.
The special value CEU_WCLOCK_NONE represents the absence of wall-clock awaits.
Note: us can be sometimes less or equal to zero.
By default this macro is not defined, hence, the environment should call ceu_go_wclock periodically.
  • ceu_out_event(id, len, data)
Executes whenever the program emits an output event.
This macro specifies the side effect associated with output events.
The returned integer becomes the result of the emit in the program.
id is a number that identifies the event (see constants); len is the size of the event type; data is a pointer to the value emitted.
  • ceu_out_event_XXX(data)
Per-event version of ceu_out_event(id,len,data).
XXX is the name of the event.
If this macro is defined for a given event, only this macro is called on the occurrence of that event.

6.1.3 Constants & Defines

The following constants and defines are generated by the Céu compiler to be used by the environment.

  • CEU_WCLOCKS, defined if the program uses wall-clock awaits.
The environment can conditionally compile code for calling system timers and ceu_go_wclock.
  • CEU_ASYNCS, defined if the program uses asynchronous blocks.
The environment can conditionally compile code for calling ceu_go_async.
  • CEU_FUNC_XXX, defined for each called C function.
XXX is the name of the function (e.g. CEU_FUNC_printf).
  • CEU_IN_XXX, defined for each input event.
Every external input event has a unique identifier associated with a number.
The identifier is the name of the event prefixed with CEU_IN_ (e.g. CEU_IN_Button).
  • CEU_OUT_XXX, defined for each input event.
Every external output event has a unique identifier associated with a number.
The identifier is the name of the event prefixed with CEU_OUT_ (e.g. CEU_IN_Led).
As an example, consider the following Céu definitions:
   input int A, B;
   output void C, D;
The compiler may generate the following constants for them:
   #define CEU_IN_A    0;
   #define CEU_IN_B    5;
   #define CEU_OUT_C   0;
   #define CEU_OUT_D   1;
Two input events never have the same associated value. The same holds for output events.
The values between input and output events are unrelated.
Also, the values need not to be continuous.

6.1.4 Types

Céu expects the following scalar types to be defined by the environment: s32, s16, s8, u32, u16, and u8. They correspond to signed and unsigned variations of the referred sizes in bits.

Follows an example of possible definitions for the scalar types:

   typedef long long  s64;
   typedef long       s32;
   typedef short      s16;
   typedef char       s8;
   typedef unsigned long long u64;
   typedef unsigned long      u32;
   typedef unsigned short     u16;
   typedef unsigned char      u8;

These types are used internally by the language runtime, and can also be used by programmers in Céu programs. For instance, Céu internally uses a u64 type to represent wall-clock time.

6.2 Compiler

Céu provides a command line compiler that generates C code for a given input program. The compiler is independent of the target platform.

The generated C output should be included in the main application, and is supposed to be integrated with the specific platform through the presented API.

The command line options for the compiler are as follows:

   ./ceu <filename>              # Ceu input file, or `-´ for stdin
       --output <filename>       # C output file (stdout)
       --defs-file <filename>    # define constants in a separate output file (no)
       --join (--no-join)        # join lines enclosed by /*{-{*/ and /*}-}*/ (join)
       --dfa (--no-dfa)          # perform DFA analysis (no-dfa)
       --dfa-viz (--no-dfa-viz)  # generate DFA graph (no-dfa-viz)
       --m4 (--no-m4)            # preprocess the input with `m4´ (no-m4)
       --m4-args                 # preprocess the input with `m4´ passing arguments in between `"´ (no)

The values in parenthesis show the defaults for the options that are omitted.