The Chirp Language Specification
Version 2

Li Xu
Department of Computer Science
University of Massachusetts Lowell
Lowell, MA 01854

1  Introduction

Chirp is a simple C-like imperative language targeting embedded microcontrollers used in personal robot devices, eg. Parallax Scribbler robots. Processors used in this domain of embedded devices are highly cost-sensitive and generally have only limited set of resources and operation commands. Software running on such devices typically has no operating system support; instead, user programs take direct control of hardware through dedicated hardware control operations. Chirp is designed to support programming in this domain with simplified data types and control constructs reflecting common hardware features. To allow high-level access of hardware control operations, Chirp provides the special abstraction of System interface functions which programmers can use to control various I/O devices, eg. sensors and motors, of the system. Chirp compiler will translate System interface function calls to hardware control commands as part of the compiled program. The compiled code can then be uploaded to the device and run directly on hardware.

Chirp (version 2) is evolved from the original Chirp (v1) specification which targets the Cricket robot controller []. The first implementation target of Chirp v2 is the Parallax Scribbler robot, the hardware control is done through the System.Scribbler interface functions. In the future, support for other targets will be added with similar interface functions. Another goal of Chirp is to serve as a target compiler language for introductory and advanced courses on compiler construction. This document describes the language features and specification of Chirp.

2  Chirp Syntax

Chirp has a syntax similar to C. Chirp programs consist of variable and function definitions. Chirp variables are of several predefined types; user functions consist of statements including assignments, control flow statements, function calls, etc. Chirp is case sensitive, eg. Foo and foo are distinct names. Chirp keywords are reserved — the programmer cannot use a Chirp keyword as the name of a variable or function. The set of keywords include data type and statement keywords: int, byte, nib, bit, pin, rom_int, rom_byte, if, else, loop, while, until, for, return.

The following characters have special meaning in a Chirp program:

{ } < > = + - * / % ! [ ] ( ) . , ; : "

Chirp accepts C/C++ style comments: multi-line comments are delimited by matching /* at the beginning and */ at the end; single-line comments follow // until the end of the line.

Chirp identifiers start with a letter or the underscore character which is then followed by letter, underscore or digit characters. Chirp identifiers are used for variable, array and function names. The lexical tokens for Chirp identifiers are defined as follows:

Lettera | b | c | ... | z | A | B | ... | Z | _
Digit0 | 1 | 2 | ... | 9
IDLetter ( Letter | Digit )*

Chirp constants include integer and string constants. String constants are quoted by double quotes and consist of character sequence of non-quote characters. Chirp does not have a string type, and string constants are used directly in Chirp programs.

Chirp supports the following boolean, relational and arithmetic operators:

Chirp boolean values follow the C convention: 0 represents boolean false and non-0 value represents true.

The EBNF grammar of Chirp is shown in Figure 1. The lexical tokens are in the typewriter font.


program( var_def | func_def )*
var_def( const )? data_type ID ( = INT )? ;
  | data_type ID ( [ INT ] )+ ;
data_typeint | byte | nib | bit | pin ( INT )
  | rom_int | rom_byte
func_def( data_type | void ) ID ( arg_list ) func_body
arg_list( data_type ID ( , data_type ID )* )?
func_body{ ( var_def )* ( stmt )* }
stmtassign_stmt ; | if_else_stmt | loop_stmt | return_stmt ; | break_stmt ;
  | func_call ; | block_stmt
assign_stmtID ( [ expr ] )* = expr
if_else_stmtif ( expr ) stmt ( else stmt )?
loop_stmtloop ( while ( expr ) )? block_stmt ( until ( expr ) )?
  | for ID ( expr : expr ( : expr )? ) block_stmt
return_stmtreturn ( expr )?
break_stmtbreak
func_callID ( . ID )* ( ( expr ( , expr )* )? )
block_stmt{ ( stmt )* }
expr! relational_expr | relational_expr ( ( && | || ) relational_expr )*
relational_exprarithmetic_expr ( ( == | != | <= | < | >= | > ) arithmetic_expr )*
arithmetic_exprterm ( ( + | - ) term )*
termfactor ( ( * | / | % ) factor )*
factorID ( [ expr ] )* | INT | STRING | func_call | ( expr )
Figure 1: Chirp grammar

3  Overview of Chirp Language Constructs

As shown in Figure 1, Chirp syntax is close to C. This is intensional, users who are familiar with C/C++ or Java languages can quickly pick it up and start programming robots using Chirp. However, as Chirp is designed to support embedded robot control rather than general-purpose computing, the feature set of Chirp is greatly simplified and only include data types and control constructs essential for writing embedded robot control programs.

Chirp supports numeric data types, such as int and byte types. Reflecting the capability of the underlying hardware, Chirp also has bit, nib (4-bit), pin (1-bit with pin number) for I/O pin data, and rom_int and rom_byte for ROM based data. Users can define variables and arrays of the base types. Unlike general-purpose languages such as C, Chirp does not have abstract data type constructs for building user-defined types, reflecting again the characters of its target domain.

User computation in Chirp is done through function definitions. User functions can take arguments, define local variables, execute Chirp statements, and return a data value as result or null. Like C, the main function in Chirp program serves as the entry point of user code.

3.1  Scribbler Target

Chirp can be used to program the Scribbler robots. Scribblers are manufactured by Parallax Inc []. Scribblers run on embedded BASIC Stamp 2 (BS2) microcontrollers. As a highly constrained embedded system, a Scribbler has only 32 bytes RAM (for program variables) and 2K bytes ROM (code and data). The BS2 microcontroller has 16 programmable I/O pins which connect to Scribbler’s 9 sensors, 2 DC motors, 3 LEDs, an on-board speaker and serial port for PC communication. Parallax provides a BASIC-style low-level command set (42 PBASIC commands) to program the robot [, ].

The pin assignments of Scribbler sensors and motors are listed in Figure 2.


ComponentsPin #
Light Sensor: left2
Light Sensor: center1
Light Sensor: right0
Line Sensor: enable3
Line Sensor: left5
Line Sensor: right4
Stall Sensor7
LED: left10
LED: center9
LED: right8
Speaker11
DC Motor: left13
DC Motor: right12
Obstacle Sensor: detector6
Obstacle Sensor: left15
Obstacle Sensor: right14
Figure 2: Scribbler pin specification

Chirp data types match directly to the target data types on BS2 microcontroller:

User can define variables with int, byte, nib, bit and pin types. The variables will be allocated in RAM memory. User can also use rom_int and rom_byte types to specify ROM-based data. Computation in Chirp is realized through expressions and statements. Chirp supports C-like general expressions, in which variable and array references and constants are used as building blocks to construct more complex expressions, including arithmetic, relational and boolean expressions. Expression values are used in Chirp statements. Chirp supports a set of simplified control constructs. Allowable statements are assignments, if-else conditional statements, unconditional and conditional loops, for-loops with a calculated loop count, function call and return. Like C, Chirp supports control abstraction through functions. The function body is a sequence of Chirp statements.

To support device control, Chirp provides special System “interface” functions. The System interface aggregates hardware I/O functions within the System namespace. Users can call System interface functions to control hardware devices, such as robot motors and sensors.

3.2  Example Chirp Program

An example Chirp program for Scribbler robot is shown in Figure 3.


 const int do = 391; // note Do's frequency 
 const int re = 494; // note Re
 const int mi = 523; // note Mi
 int tune_time;

 bit stalled;
 pin(11) speaker;

 void startTune() {
   tune_time = 200;  // 200ms
   System.Scribbler.sound(speaker, tune_time, do);
   System.Scribbler.sound(speaker, tune_time, re);
   System.Scribbler.sound(speaker, tune_time, mi);
 }

 void checkState() {
   Scribbler.senseStall(stalled);
   if (stalled) {
     System.Scribbler.setLED(1, 1, 1);
     System.Scribbler.moveBackward(5, 5, 1000);
     System.Scribbler.moveLeft(5, 5, 1000);
   } else {
     System.Scribbler.setLED(0, 0, 0);
   }
 } 
 
 void main() {
   startTune();
   loop {
     System.Scribbler.moveForward(5, 5, 0);
     checkState();
   }
 }
Figure 3: Example Chirp program

It consists of variable definitions and three functions (including the main function): the robot starts by playing music notes on the speaker pin (Pin 11), then starts the motors and moves forward; it checks the stall sensor to see if it hits obstacles, and if so, it turns on all three LEDs, backs away and turns left. The code calls the System.Scribbler interface functions to control the robot.

4  Chirp Specification

4.1  Data Types and Conversion

Chirp data types are: int, byte, nib, bit, pin, rom_int, rom_byte. Type conversions in Chirp are implicit, that is, the compiler will determine the need of type conversions in expression evaluation if mixed types are used.

Similar to C, Chirp uses integer types to represent boolean values: 0 represents boolean false and any non-zero value represents boolean true.

Chirp also supports array types with array elements of the basic types. Array dimensions are fixed integer constants.

4.2  Functions and Variables

User can define functions in Chirp similar to C. Functions can take arguments, define local variables, and specify return value. Users can define global, function formal and local variables of basic and array types.

4.3  Assignment Statement

The assignment statement requires that its left-hand side to be a variable or array element and its right-hand side an expression.

4.4  If-Else Statement

The if-else statement evaluates the condition expression to a boolean value (using the zero/non-zero numeric value as boolean result) and executes the following “then” or “else” branch respectively. The else statement is always bound to the nearest unbound if statement to resolve ambiguity.

4.5  Loop and Break Statements

Chirp provides unconditional and conditional loops with while and until condition constructs. The loop statements will either execute the loop body in repetition (infinite loop), or evaluate the while (loop-while-body) or until (loop-body-until) expression and iterate the loop body depending on the condition: for while loop, the loop body will be executed if the condition is true; for until loop, the loop body will terminate if the condition is true. Chirp also has for-loop statements, in which the loop counter variable iterates from the loop-start value to the loop-end value with an optional step increment (for-id-start-end-step). The break statement can be used in the loop body to terminate loop iteration.

4.6  Return Statement

The return statement terminates the function and returns the control flow to the caller.

4.7  Function Call

Chirp functions are invoked by calling the named functions. Function calls need to supply the required arguments and function names should be qualified with appropriate interface names.

4.8  Block Statements

Similar to C, Chirp allows user to use curly braces to aggregate statements into code blocks.

4.9  Expressions

Chirp expressions compute values of the basic types. As boolean values are represented by integer values, Chirp defines boolean and, or and not operator to evaluate boolean values. The relational operators are ==, !=, <=, <, >=, >. Chirp also supports common arithmetic operations.

4.10  Interfaces

The interface construct aggregates related I/O interface functions. The System interface consists of a list of interface functions. Interface functions can be called through the qualified interface and function names.

5  Acknowledgments

This work has been supported by NSF grant DUE-0737054.


This document was translated from LATEX by HEVEA.