Not Quite C Compiler version 1.0 b1

Similar documents
NQC User Manual. Version 2.2 r1, written by Dave Baum

NQC User Manual. Version 2.0, written by Dave Baum

Lexical Considerations

fpp: Fortran preprocessor March 9, 2009

Rule 1-3: Use white space to break a function into paragraphs. Rule 1-5: Avoid very long statements. Use multiple shorter statements instead.

1 Lexical Considerations

Lexical Considerations

COMP322 - Introduction to C++ Lecture 02 - Basics of C++

GNU ccscript Scripting Guide IV

Appendix A. The Preprocessor

3 PREPROCESSOR. Overview. Listing 3-0. Table 3-0.

Lecture Outline. COMP-421 Compiler Design. What is Lex? Lex Specification. ! Lexical Analyzer Lex. ! Lex Examples. Presented by Dr Ioanna Dionysiou

ASML Language Reference Manual

The SPL Programming Language Reference Manual

Control flow and string example. C and C++ Functions. Function type-system nasties. 2. Functions Preprocessor. Alastair R. Beresford.

Decaf Language Reference

Lecture 2: C Programming Basic

Typescript on LLVM Language Reference Manual

Inno Setup Preprocessor: Introduction

COSC 2P91. Bringing it all together... Week 4b. Brock University. Brock University (Week 4b) Bringing it all together... 1 / 22

EDIABAS BEST/2 LANGUAGE DESCRIPTION. VERSION 6b. Electronic Diagnostic Basic System EDIABAS - BEST/2 LANGUAGE DESCRIPTION

Contents. Jairo Pava COMS W4115 June 28, 2013 LEARN: Language Reference Manual

TED Language Reference Manual

Review of the C Programming Language for Principles of Operating Systems

Project 2 Interpreter for Snail. 2 The Snail Programming Language

C and C++ 2. Functions Preprocessor. Alan Mycroft

c) Comments do not cause any machine language object code to be generated. d) Lengthy comments can cause poor execution-time performance.


\n is used in a string to indicate the newline character. An expression produces data. The simplest expression

Language Reference Manual simplicity

Here redirection. Case statement. Advanced Unix Tools Lecture 6 CS214 Spring 2004 Friday March 5, 2004

Decaf Language Reference Manual

Have examined process Creating program Have developed program Written in C Source code

The PCAT Programming Language Reference Manual

Review of the C Programming Language

A Fast Review of C Essentials Part I

CSc 10200! Introduction to Computing. Lecture 2-3 Edgardo Molina Fall 2013 City College of New York

Lecture 2 Tao Wang 1

CHAD Language Reference Manual

egrapher Language Reference Manual

Chapter 2: Overview of C++

BLM2031 Structured Programming. Zeyneb KURT

EL6483: Brief Overview of C Programming Language

GAWK Language Reference Manual

Slang Reference Manual

Basics of Java Programming

A Short Summary of Javali

GOLD Language Reference Manual

ARG! Language Reference Manual

2.1. Chapter 2: Parts of a C++ Program. Parts of a C++ Program. Introduction to C++ Parts of a C++ Program

Weiss Chapter 1 terminology (parenthesized numbers are page numbers)

bc an arbitrary precision calculator language version 1.06

Unit 4 Preprocessor Directives

Absolute C++ Walter Savitch

Model Viva Questions for Programming in C lab

Command Interpreters. command-line (e.g. Unix shell) On Unix/Linux, bash has become defacto standard shell.

RCX Tutorial. Commands Sensor Watchers Stack Controllers My Commands

Features of C. Portable Procedural / Modular Structured Language Statically typed Middle level language

Reference Grammar Meta-notation: hfooi means foo is a nonterminal. foo (in bold font) means that foo is a terminal i.e., a token or a part of a token.

Java Bytecode (binary file)

Sprite an animation manipulation language Language Reference Manual

Cisco IOS Shell. Finding Feature Information. Prerequisites for Cisco IOS.sh. Last Updated: December 14, 2012

Chapter 1 Summary. Chapter 2 Summary. end of a string, in which case the string can span multiple lines.

Appendix. Grammar. A.1 Introduction. A.2 Keywords. There is no worse danger for a teacher than to teach words instead of things.

6.096 Introduction to C++

Full file at C How to Program, 6/e Multiple Choice Test Bank

NQC Programmer's Guide

Control Flow. COMS W1007 Introduction to Computer Science. Christopher Conway 3 June 2003

Intro to Computer Programming (ICP) Rab Nawaz Jadoon

Flow Control. CSC215 Lecture

FRAC: Language Reference Manual

Final thoughts on functions F E B 2 5 T H

Errors During Compilation and Execution Background Information

A Fast Review of C Essentials Part II

JME Language Reference Manual

CSCI 1061U Programming Workshop 2. C++ Basics

Key Differences Between Python and Java

The Chirp Language Specification

Chapter 7: Preprocessing Directives

Introduction to Programming Using Java (98-388)

Documentation for LISP in BASIC

Learning Language. Reference Manual. George Liao (gkl2104) Joseanibal Colon Ramos (jc2373) Stephen Robinson (sar2120) Huabiao Xu(hx2104)

Fundamental of Programming (C)

CS201 Some Important Definitions

3. Except for strings, double quotes, identifiers, and keywords, C++ ignores all white space.

C++ Programming Basics

Pace University. Fundamental Concepts of CS121 1

Intermediate Programming, Spring 2017*

AN OVERVIEW OF C, PART 3. CSE 130: Introduction to Programming in C Stony Brook University

C++ Programming Lecture 1 Software Engineering Group

IC Language Specification

Mirage. Language Reference Manual. Image drawn using Mirage 1.1. Columbia University COMS W4115 Programming Languages and Translators Fall 2006

Introduction to Computers and C++ Programming p. 1 Computer Systems p. 2 Hardware p. 2 Software p. 7 High-Level Languages p. 8 Compilers p.

public class Foo { private int var; public int Method1() { // var accessible anywhere here } public int MethodN() {

Handy Cricket Programming

Chapter 2: Functions and Control Structures

CSCI 171 Chapter Outlines

My Favorite bash Tips and Tricks

OBJECT ORIENTED PROGRAMMING USING C++

Chapter 2: Using Data

Transcription:

Not Quite C Compiler version 1.0 b1 Introduction NQC is a simple language for programming the LEGO RCX. The preprocessor and control structures of NQC are very similar to C. NQC is not a general purpose language - there are many restrictions that originate from actual limitations and lack of detailed information about the RCX itself. A NQC program consists of tasks and subroutines. The first task is started automatically when the program is run, the remaining tasks can be started by the program. Subroutines can be shared across all of the tasks. The compiler itself understands very little of the RCX. Most of the RCX functionality (such as playing a sound, reading an input sensor, etc) is added by the rcx.nqh include. This file is included automatically by the compiler (unless -s is specified on the command line). The file itself defines many high level macros (such as PlaySound()) that are implemented in terms of low level primitives within the compiler itself. This approach means that new "system" features can be easily added to rcx.nqh without modifying the compiler or introducing new keywords. Usage The nqcc command line useage looks like this: nqcc [-s] [-d] [-l] [-e] [-o output_file] [-Dsym=[def]] [-Usym] source_file The default behavior is to compile the specified source_file to an output file that is named by replacing the ".nqc" extension of the source filename with ".rcx". If the source filename does not end with ".nqc", the default output filename is the source filename with ".rcx" appended to it. The "-o" option may be used to specify an alternate name for the output file. The source file name "-" causes nqcc to read stdin as the source file. In this case, the -o option must be used to explicitly name an output file if one is desired. The "-s" option prevents the compiler for automatically including "rcx.nqh" before compiling the source file. The "-d" option causes nqcc to atttempt downloading the program to an RCX after compiling it. If an output file was not explicitly named ("-o" option), then no output file is generated. The "-l" option writes a bytecode listing to stdout.

The "-e" options sends compiler error messages to stdout instead of stderr. This option is only needed when running nqcc under Win95, which does not support redirection of stderr from the standard shell (command.com). The following examples show how to redirect stderr (to a file called errors) under other platforms: MPW: nqcc test.nqc errors WinNT: nqcc test.nqc 2>errors The -Dsym[=def] option defines preprocessor symbol sym to the value def. The -U option undefines preprocessor symbol def. Two environment variables are used by nqcc: NQCC_INCLUDE - this environment variable can be used to specifiy a directory to search for include files in addition to the current working directory. When building filenames, nqcc simply concatentates the value of NQCC_INCLUDE with the target filename, so NQCC_INCLUDE must end in the appropriate directory separator ( \ for PC, : for Mac, / for Unix). RCX_PORT - this environment variable can be used to specify a serial port other than the default (COM1 for PC, Modem for Mac). The value of RCX_PORT should be the name of the port (for example "COM2" for the PC, or "b" for the Mac s printer port). Preprocessor The preprocessor implements the following directives: #include, #define, #ifdef, #ifndef, #if, #elif, #else, #endif, #undef. The #include command works as expected, with the caveat that the filename must be enclosed in double quotes: #include "foo.nqh" The #define command is used for simple macro substitution. Redefinition of a macro is an error (unlike in C where it is a warning). Macros are normally terminated by the end of the line, but the newline may be escaped to allow multi-line macros: #define foo(x) do { bar(x) \ baz(x) } while(false) Conditional compilation works similar to the C preprocessor. Expressions in #if directives use the same operators and precedence as in C. C and C++ style comments are supported /* this is a comment */

// another comment Tasks and Subroutines Each program is made up of tasks and subroutines, each of which is composed of statements. Each program must have at least one task (named "main"), which serves as the entry point of the program. A task looks like this: task task_name { statements } Tasks can be started or stopped with the following statements start task_name stop task_name Subroutines look very similar to tasks, but use the sub keyword. Note that there are no parameters or return values for subroutines. The only variables available are global variables. sub sub_name { statements } Subroutines are called just like in C, with the caveat that there are not parameters or return value: sub_name() Due to a limitation in the RCX firmware, subroutines are not allowed to make subroutine calls (either to themselves or another subroutine). Statements are contained within tasks and subroutines. Like C, the semicolon ( ) is used as a statement terminator. Groups of statements can be combined into a a block using braces ( { and } ). Values Many statements (such as variable assignment, or conditional testing) make use of "values". A value can be many things: a constant, the contents of a global variable, a random number, the reading from an input sensor, etc. Each of these is covered in more

detail below. In addition, some of the high level commands may take constants and/or values as arguments. In the description of a command its arguments will be noted as either "const" or "value". "const" arguments must be a numeric constant. "value" arguments may be either a numeric constant or another sort of value (such as a variable). Note that not all value types are legal for all commands that use values. Numeric constants can be written as either decimal (e.g. 123) or hexidecimal (e.g. 0xABC). Presently, there is very little range checking on constants, so using a value larger than expected can have unpredictable results. Constants can be combined using the standard arithmetic operators (+, -, *, /, %, <<, >>, &,, ^, ~). Precedence and associativity are the same as C. Parentheses can be used to group lower precedence operations together. The RCX provides 32 global variables. In order to use variables in your program, you must first declare them: int foo All of the variables are global (even across multiple programs), hence they must be decalred outside the scope of any tasks and subroutines. Variables can be assigned values using the following assigment operators: var = value var += value var -= value var *= value var /= value Note that general expressions (e.g. a = b + c) are only supported for compile time constants and not for runtime evaluation: int foo,bar task main { foo = 2 + 3 // legal foo = bar + 2 // illegal } Other value types inclue: Input(n) Timer(n) Random(n) Message() Watch() - current value of sensor n, where n=0-2 - current value of timer n, where n=0-2 - random number between 0 and n-1? (not sure about the range) - value of the last received IR message - value of the system clock Note: the rxc.nqh file defines macros IN_1, IN_2, and IN_3 as Input(0), Input(1), and Input(2), respectively.

Control Structures Conditions can be either a comparison beteen two values, or one of the predefined constants "true" and "false". There are six relations (<, >, <=, >=, ==,!=). Conditions may be combined using && and, or negated with!". Here are the control structures: if (condition) statement if (condition) statement else statement while(condition) statement do statement while(condition) repeat(value) statement wait (condition) statement The first four structures are identical to their counterparts in C. The "repeat" structure causes a statement to be executed a number of times. This number does not have to be a constant, for example it could be the value of a global variable, however the number is only evaluated prior to starting the loop (as opposed to the "for" structure in C which evaluates the condition before each iteration). The RCX allows "repeat" loops to be nested (maintaining its own "stack" of look counters). The "break" statement is also legal within repeat loops, although it has a rather unexpected result when used within a nested loop. Although the control flow will be broken, there is no way to pop the old counter off the internal stack, so the enclosing loop will be using the wrong counter when it starts repeating. This cannot be reliably checked at compile time since the internal repeat stack is shared across subroutine calls. The "wait" structure executes the body until the condition becomes true. It is actually implemented as a macro (so be careful of side effects). It it handy when waiting for something to happen: wait(in_3 == 1) // wait for sensor 3 to have value 1 Several other control flow statements are supported: break continue return "break" and "continue" can be used within "do" and "while" loops. "return" can be used to exit a subroutine before getting to its end. Sensors The constants IN_1, IN_2, and IN_3 can be used to either read an input sensor, or to specify a sensor. Sensor types are defined by IN_SWITCH, IN_LIGHT, IN_ANGLE, IN_PULSE, and IN_EDGE. The Sensor() function is used to initialize the sensor:

Sensor(value sensor, const type) Some sensor types (such as the IN_ANGLE type) allow you to "reset" the sensors internal counter with the following command: ClearSensor(value sensor) The only supported value types for "sensor" in the above two examples are numeric constants and Input(n) - all other types have undefined behavior. Here s a brief example that configures sensor 1 as a switch, then waits for it to be pressed before playing a sound. Sensor(IN_1, IN_SWITCH) wait (IN_1 == 1) PlaySound(0) The macros IN_1, IN_2, and IN_3 are equivalent to Input(0), Input(1), and Input(2) and can be used anywhere that a runtime value is legal (such as setting a variable, checking a condition, etc). Motors The constants OUT_A, OUT_B, and OUT_C refer to the three outputs. They can be combined (using + or ) in order to specify multiple outputs. OUT_FULL is a constants that represents full speed for a motor. Here s how to turn on all three motors for 1 second: Fwd(OUT_A + OUT_B + OUT_C, OUT_FULL) Sleep(100) Off(OUT_A + OUT_B + OUT_C) These commands control motors: Fwd(const outs, value speed) // turn motor(s) on forwards Rev(const outs, value speed) // turn motor(s) on backwards Off(const outs) // stop motor(s) Other Commands PlaySound(const n) // play system sound #n PlayNote(const freq, const duration) // play a note Sleep(value v) // sleep for v ticks (100 ticks per second) Display(value v) // set the dispaly mode as follows:

Note: display modes for "Display" are as follows: 0 = system clock, 1-3 = input channel, 4-6 = output channel. To show the value of the third input, use "Display(3)", not "Display(IN_3)". The later command will read the value of sensor 3, and use that value as the argument to the display command (e.g. if the sensor s value is 0, then the system clock will be displayed). Yeah, this is pretty stupid, but its how the RCX works. SendMessage(value m) // send low 8 bits of m as an IR message ClearMessage() // clear the last received IR message ClearTimer(const n) // clear timer #n Data Logging The RCX supports a Datalog feature. Using this feature requires three steps: 1) Set the datalog size 2) Add data points to the datalog 3) Upload the datalog to a host You can set the datalog size with the following command SetDatalog(const n) // create datalog for n points Point can be added with Datalog(value v) // add v to the datalog Only certain types of values may be added (variables, timers, sensor readings, the system clock). Some (or all) of the datalog may be uploaded at any time as follows: UploadDatalog(const index, count count) "index" is the first data point to upload, and "count" is the number of points to upload. Each entry in the datalog uses three bytes - the first byte is the type of entry, the next two are a 16 bit value in little endian format. If you set the size of the datalog to N, then there are actually N+1 entries - the first one (at index 0) is the number of data points collected so far (type = 0xff), while the remaining ones (index 1 - N) are the points themselves. Here are the type codes for normal data points: 0x00 - value of a variable 0x20 - value of a timer 0x40 - value of a sensor 0x80 - value of the clock Keywords

The following keywords are used in nqcc: asm if stop break int sub continue repeat task do return true else start while false Grammar program : unit_list unit_list: unit_list unit unit : int id_list task id block sub id block id_list : id_list, id id block : { stmt_list } stmt_list : stmt_list stmt stmt : block asm { bytes } while ( condition ) stmt do stmt while ( condition ) repeat ( value ) stmt break continue if ( condition ) stmt if ( condition) stmt else stmt id assign value start id

stop id id ( ) return bytes value : bytes, expr expr : expr id @ expr assign : = += -= *= /= expr : number expr binop expr - expr ~ expr ( expr ) [ value ] binop : + - * / % & ^ << >> condition : value relop value! condition condition && condition condition condition ( condition ) true false relop : ==!= < > <= >= For Hackers Only NQC contains very little in the way of RCX specific functions. Support for controlling motors, reading sensors, etc. is provided in the rcx.nqh file. This section explains some of the low level constructs used within these definitions.

Internally, many of the RCX operations use "values", which are essentially a form of typed data. Each value has a "type" and a "index", which together specify a sort of effective address for the runtime value. Of course, one of the types is "constant", in which case the effective value is equal to the index itself. Other types include reading an input sensor or generating a random number. The compiler can perform arithmetic operations only on compile time constants. Certain statement (such as conditional clauses) require values, and constants are automatically promoted to values in these situations. However, sometimes it is desireable to specify the type/index pair directly. This can be done by using the @ operator, which converts a 24 bit number directly to a value. The lower 16 bits are the index, the next 8 are the type code. For example, since the type code for "constants" is 2, the following value is equal to 0x123: @0x20123 The type code for variables is 0, so the following refers to variable 7: @0x00007 This is very different from 0x00007, which equals the number 7. It would ve been much nicer if LEGO had made the type code for constants equal to 0, but we have to live with this hack. Sometimes it is necessary to convert a value back into its "effective address". This is done by enclosing the value in brackets: [ Random(7) ] The effective address is constant, thus can be manipulated with the compiler s arithmetic operators. Finally, the "asm" statement allows most primitives to be implemented: asm { data } "data" is one or more numbers, separated by commas. The asm statement emits the literal data contained within its braces. The data bytes for an asm statement must be compile time contsatnts, not runtime values.