Pico Logo

August 14, 2026 · View on GitHub

Installation

From the Releases page, download the UF2 file for your device and the logo.img file. On your SD Card, copy the logo.img file into the root folder and insert it into the PicoCalc.

Flash the PicoCalc with the latest release and reboot your PicoCalc:

  1. Make sure your PicoCalc is off.
  2. Push and hold the BOOTSEL button, accessible through the back of the PicoCalc, while connecting your PicoCalc with a USB cable to a computer. Use the USB port of the Pico, closest to the bottom of the device.
  3. Release the BOOTSEL button once your Pico appears as a mass storage device called RPI-RP2.
  4. Drag and drop the Pico Logo UF2 file onto the RPI-RP2 volume. Your Pico will reboot.
  5. Disconnect the USB cable and turn on the PicoCalc. You are now running Pico Logo.

You should see:

Copyright 2025-2026 Blair Leduc
Welcome to Pico Logo.
?_

The question mark, ? is the prompt. When the prompt is on the screen, you can type something. The flashing underscore, _ is the cursor. It appears when Logo wants you to type something and shows where the next character you type will appear.

Restore the default filesystem

At the prompt, enter:

.restore "/sd/logo.img

This will format and restore the factory filesystem contents. You can now remove the logo.img file from the SD Card.

References

This reference manual contains content that is collected from:

===

Contents

{{TOC}}

===

Introduction

Logo Programs

A Logo program is a collection of procedures.

For example, a program to draw a house consists of these procedures: house, box, tri, right, forward, and repeat. Of these, the last three are primitives. The first three are user-defined procedures, built out of Logo primitives.

to house
  box 
  forward 50
  right 30
  tri 50 
end 

to box 
  repeat 4 [forward 50 right 90] 
end

to tri :size
  repeat 3 [forward :size right 120] 
end 

We are assuming that you have had some experience with Logo and have built up an intuitive model of what Logo is about. Here we give a more formal model. This model is just another way to think about Logo. It is not meant to replace your current way of thinking, but rather to enhance it.

The actual Logo system is very complicated. It will help if we consider a formal description of Logo, and then Logo as it really is. We begin our formal description by restricting ourselves to a part of Logo, which we'll call formal Logo; we then relax the restrictions in order to describe the language you actually use, which we'll call relaxed Logo.

Every instruction in formal Logo works without change in relaxed Logo. Conversely, anything that can be done in Logo can be done in formal Logo, but you will immediately recognize situations where formal Logo forces idioms that no one would actually use. For example, if you are experienced in Logo you will notice that numbers look peculiar in formal Logo: they are quoted. Since numbers are words, you can quote them in relaxed Logo as well. But we do so very rarely; in relaxed Logo, numbers are self-quoting.

Procedures and inputs: We assume that you know what procedures are, at least on an intuitive level. Here we develop some more precise ways to talk about them.

In formal Logo, every procedure requires a definite number of inputs. These inputs are always one of two kinds: they may be words or they may be lists. They may be given directly, as in forward "100, or indirectly through the mediation of another procedure, as in forward sum "60 “40. Both of these examples have the same effect. If an input is given directly as a word, it must be preceded by a quote mark, as in print "forward. If it is given directly as a list, it is surrounded by square brackets, as in print [How are you?].

Words and lists: A word is made up of characters. A list is made up of elements enclosed in square brackets, with spaces between elements; an element is either a word (without quotes) or a list.

Naming things: The name of a procedure, input, or variable is a word. Logo does not care if a name is in lower or upper case. For example, the following are regarded as being the same:

forward "100
FORWARD "100

The name is remembered using the case that is used in the definition.

Property Lists: Any Logo word can have a property list associated with it. A property list consists of an even number of elements. Each pair of elements consists of a property, and its value, a word or a list.

Expressions: A procedure name followed by the required number of inputs is an expression. More generally, an expression is

  • a quoted word,
  • list, or
  • an (unquoted) procedure name followed by as many expressions as the procedure requires.

If this seems complicated, look at an example. repeat is a procedure that requires two inputs.

This is an expression:

repeat "3 [fd "10] 

The following is also an expression:

repeat sum "2 "1 [fd "10]

In this case the first input is not a quoted word, but an expression involving another procedure, sum.

The following is also an expression:

repeat sum "3 "1 sentence "fd "10 

Commands and operations: There are two kinds of procedures in Logo. Those (like sum) that produce a Logo object are called operations. The others (like print) are called commands.

With these definitions we can define a Logo instruction.

A Logo instruction is a particular kind of expression. It starts with a procedure name, and that procedure must be a command. All other procedures in the expression must be operations.

Why does it matter whether an expression is an instruction or not? Consider

sum "3 "4 

This is an expression, but it is not a Logo instruction.

sum will produce a number; but simply writing sum "3 "4 does not state what is to be done with the number. In fact, Logo will give an error message saying I don't know what to do with 7. Some programming languages would allow this and simply print the 7. In designing Logo we preferred to make every important act explicit; if you want something to be printed you should say so.

Everything that can be done in Logo can be done using formal Logo. But we have allowed some other idioms, either to make the language feel more natural or to eliminate large amounts of typing.

Here we list some important relaxations of Logo. Others are mentioned in the body of the manual. See also Parsing.

Numbers: In formal Logo, all words used as direct inputs, including numbers, must be quoted. In relaxed Logo, numbers are self-quoting: the quote marks are unnecessary. For example,

sum 3 4 

A number is a word made up of digits; it may also contain a minus sign, a period, and an E or N. See (Arithmetic Operations)[#arithmetic-operations].

?print 1e4
10000
?print 1n4
0.0001

Infix procedures: Formal Logo uses only prefix procedures. Thus addition is expressed by sum "3 “4. In relaxed Logo you can also use the infix form 3 + 4. Similarly with multiplication, subtraction, and division. See Arithmetic Operations.

Variable number of inputs: In formal Logo, every procedure has a fixed number of inputs. In relaxed Logo, several procedures can have variable numbers of inputs. When you use other than the expected number of inputs you must enclose the expression in parentheses:

(sum 3 4 5 6 7 8) 

Dots: A familiar feature of relaxed Logo is the use of dots (:). In formal Logo, :x is written as thing "x.

Parentheses for grouping: Logo has parentheses so that you can explicitly tell Logo how to Group things. For example, consider

25 + 20 / 5

Should the addition be done first, producing 9, or should the division be done first, producing 29? Relaxed Logo follows the traditional mathematical hierarchy, in which multiplication and division are done before addition and subtraction; thus this operation first divides 20 by 5, and produces 29. To group the numbers so that addition is done first, parentheses must be used:

(25 + 20) / 5 

Commands and operations: In formal Logo, a given procedure is either a command or an operation, not both. In relaxed Logo, a procedure can be sometimes a command and sometimes an operation. run and if are examples of this. See Conditionals and Control of Flow.

The command to: In formal Logo, you define a procedure with the command define; it takes two inputs, a word (the procedure name) and a list (the definition). All the usual rules about quotes and brackets apply without exception:

define "square [ [ ] [ repeat 4 [ fd 100 rt 90 ] ] ] 

In relaxed Logo, you can define a procedure with edit and to. The command to is unusual in two ways. It automatically quotes its inputs, and it allows you to type in the lines of the procedure interactively:

?to square :size
>repeat 4 [fd :size rt 90] 
>end

As shown, when interactively defining a procedure using the command to, the prompt changes to > until a line ending with end is encountered ending the definition of the procedure. This provides feedback that you are in the middle of defining a procedure and is the only time when this prompt is used.

A Further Note on Operations

In talking about formal Logo we have been using the word produce: a procedure produces an object (called the output of the procedure). In traditional Logo terminology we say that the procedure outputs an object.

Logo Objects

There are two types of Logo things (or objects): words and lists.

A word, such as television or 617, is made up of characters (letters, digits, punctuation). A number is a kind of word.

A list, such as [rabbits television 7 [ears feet]], is made up of Logo objects, each of which can be either a word or a list. See Words and Lists.

Variables: Some General Information

A variable is a container that holds a Logo object. The container has a name and a value. The object held in the container is called the variable's value. You create a variable in one of two ways: either by using the make or name command, or by using procedure inputs.

Logo has two kinds of variables: local variables and global variables. Variables used as procedure inputs are local to that procedure. They exist only as long as the procedure is running, and will disappear from your workspace after the procedure stops running.

Normally a variable created by make is a global variable. The local command lets you change those variables into local variables. This can be very useful if you want to avoid cluttering up your workspace with unwanted variables.

to yesno: question
  local "answer
  pr :question
  make "answer first readlist
  if equal? :answer "yes [ output true ]
  output false
end

How You Might Think about Quotes

The role of quotes is best understood through the following example:

?print "heading
heading
?print heading 
180

In the first case the quotation mark (") indicates that the word heading itself is the input to print.

In the second case the input is not quoted. It is therefore interpreted as a procedure, which provides the input to print.

How You Might Think about MAKE

The effect of the command

make "bird "pigeon

can be thought of as follows. A container is given a name: bird. The word pigeon is put into the container.

Once this is done the operation thing has the following effect:

thing "bird

produces pigeon.

Dots are similar to thing; for example,

:bird

produces pigeon.

We can talk about the same situation in several ways:

bird is a variable; pigeon is its value.

bird is a name of pigeon.

bird is bound to pigeon.

pigeon is the thing of bird.

You can change what it is in the container; if you type

make "bird "sparrow 

then the container bird contains the word sparrow instead of the word pigeon.

How to Think about Procedures You Define and their Inputs

Procedures you define can have inputs. When you define a procedure, its title line specifies how many inputs it has and a name for each one. The inputs are put into the containers designated on the title line of the procedure definition in the order in which they occur. For example, the following procedure makes the turtle draw various polygons, depending upon what inputs are used.

to poly :step :angle
  forward :step 
  right :angle 
  poly :step :angle 
end 

Whatever inputs you choose-for example, 50 and 90-are put into the specified containers. The first input is always put in the container step; the second input is always put in the container angle. The first input variable, step, controls the size of the figure. The second input variable, angle, controls the shape of the figure. poly 50 90 makes the turtle draw a square; poly 50 144 makes the turtle draw a pentagram; poly 50 120 makes the turtle draw a triangle.

If the input containers already have objects in them when the procedure is run, the objects are removed but are saved. They are restored when the procedure is done. In other words, the procedure borrows the container and leaves it in its original condition when done with it. This is what is meant by saying that a variable is local to the procedure within which it occurs.

For example:

?make "sound "crash 
?print :sound 
crash 

Now we run a procedure called animal; its input variable is sound.

to animal :sound 
  if :sound = "meow [ pr "Cat stop ] 
  if :sound = "woof [ pr "Dog stop ] 
  pr [ I don't know ] 
end

If we type animal "woof, then woof is put into the sound container for the duration of the animal procedure. Afterwards, crash is restored:

?make "sound "crash 
?print :sound 
crash
?animal "woof 
Dog 
?print :sound 
crash 

Another Way to Talk about Procedures

When you use a procedure, we also say that you call that procedure. Procedures you define call other procedures. For example, the poly procedure above calls other procedures (forward and right).

poly also calls itself. This is called a recursive call.

Review of Special Characters

Quotation marks, or quotes, , used immediately before a word, indicate that it is being used as a word, not as the name of a procedure or the value of a variable.

A colon, known as dots, :, used immediately before a word, indicates that the word is to be taken as the name of a variable and produces the value of that variable.

Brackets, [ ], are used to surround a list.

Parentheses, ( ), are necessary to group things in ways that Logo ordinarily would not, and to vary the number of inputs for certain procedures. Both of these uses are described above in this introduction.

A backslash, \, tells Logo to interpret the character that follows it literally as a character, rather than keeping some special meaning it might have. For instance, suppose you wanted to use 3[a]b as a single word. You need to type 3\[a\]b in order to avoid Logo’s usual interpretation of the brackets as the envelope around a list. You have to backslash [,(,],),+,-,*,/ and \ itself.

===

Difference from other Logo interpreters

Line continuation characters are not supported.

Words with internal spaces are created using the "\" character, not using the veritcal bar notation.

Pico Logo does not support the if predicate list1 list2 form. Use (if predicate list1 list2) or ifelse predicate list1 list2 instead.

Anonymous procedures are written as named lambda expressions - a list whose first element is a list of input names, followed by the body - rather than the ?-slot template notation ([? + 1]) used by UCB/Berkeley Logo. Where Berkeley Logo would write map [? + 1] [1 2 3], Pico Logo writes map [[x] :x + 1] [1 2 3]. See List Processing for details.

Word and name comparisons are case-insensitive throughout, including equal?: equal? "Hello "hello outputs true, and a list containing "Hello is member? of a list containing "hello. Variable and procedure names are likewise case-insensitive - make "Total 1 and :total refer to the same variable. Use before?, which compares ASCII values, when exact-case comparison is needed.

All numbers are single-precision (32-bit) IEEE floating point, matching the RP2350's hardware FPU; there is no bignum or double-precision arithmetic, so results very slightly differ in their last digit from Logos that compute in double precision. Numbers printed in exponential form use n rather than a signed exponent for negative powers of ten - 1n5 means 1 × 10-5, while 1e7 means 1 × 107 - following Apple Logo's convention rather than the 1e-5 form other Logos use (a bare minus sign inside a word is easily confused with the subtraction operator).

Pico Logo has no array data type and no array/setitem primitives for O(1) indexed access; lists are the only ordered collection. .setfirst, .setbf and .setitem do mutate a list in place, as in UCB Logo, but there is no fixed-size random-access structure to mutate into.

Tail-recursive procedures run in constant space - see Tail Call Optimization, below.

Tail Call Optimization

When the last thing a procedure does is call itself - directly, as the whole of the last instruction line, or as the argument to output, or inside the taken branch of if/ifelse in tail position - Pico Logo reuses the procedure's current frame instead of pushing a new one. This is a genuine loop under the hood, not a stack of pending calls, so a tail-recursive procedure runs in constant space no matter how many times it calls itself:

?to countdown :n
>if :n = 0 [stop]
>countdown :n - 1
>end
?countdown 1000000

countdown above never runs out of recursion, because each recursive call reuses the same frame rather than adding one. This is a differentiator from classic Logo implementations, most of which count every recursive call (tail or not) against a fixed recursion depth and would overflow on a million-deep call like this one.

The optimization only reuses the frame for a procedure calling itself. Mutual recursion (a tail-calls b, which tail-calls a) and any non-tail call still consume a level of the recursion limits given under Supported Pico Boards (128 or 192, depending on the board).

===

Supported Pico Boards

Pico Logo runs on three RP2350-based boards. The interpreter and its limits are identical on every board; what differs is networking - which needs a wireless radio - and storage capacity, which depends on the flash and PSRAM fitted.

Shared by every board (the RP2350 processor):

  • 32768 nodes for procedure and variable storage
  • 24576 characters of editor buffer
  • 8192 characters in the copy buffer
  • Hardware floating-point operations

Raspberry Pi Pico 2 - 4 MB flash, no radio.

  • 192 levels of recursion (self tail-recursive calls don't count - see Tail Call Optimization)
  • 2 MB internal filesystem
  • No networking

Raspberry Pi Pico 2 W - 4 MB flash, WiFi, no PSRAM.

  • 128 levels of recursion (self tail-recursive calls don't count - see Tail Call Optimization)
  • 2 MB internal filesystem
  • WiFi (wifi.connect, wifi.scan, …) with network.resolve, network.ntp and network.ping
  • http.get and http.post over http:// only; https:// is not available, so tls? outputs false
  • HTTP responses are limited to about 2 KB (there is no PSRAM to hold a larger body)

Pimoroni Pico Plus 2 W - 16 MB flash, 8 MB PSRAM, WiFi.

  • 128 levels of recursion (self tail-recursive calls don't count - see Tail Call Optimization)
  • 8 MB internal filesystem
  • WiFi (wifi.connect, wifi.scan, …) with network.resolve, network.ntp and network.ping
  • http.get and http.post over both http:// and https://, so tls? outputs true
  • HTTP responses up to about 512 KB, held in PSRAM
  • Words may exceed 255 characters (for example the result of word or an HTTP response body), held in PSRAM

===

Startup

This section describes the feature of Logo that lets you automatically load a file into your workspace when you start up Logo. You must call the file startup. There can be only one file with the name startup, although it can include commands to load other files.

The default prefix is /, the root of the device's internal storage, so the startup file is located at /startup. You can change the startup file, with editfile.

>editfile "startup

You can bury procedures and buryname variables created in your startup file (using the startup variable!) so they are not a distraction. buryall is a good approach.

For example:

?erall
?to welcome
>pr [Hello there!]
>end
?make "startup [welcome buryall]
?save "startup

You also erase procedures and variables that are only needed for startup processing (see erase and ern).

===

Using the Logo Editor

The Logo Editor is an interactive screen-oriented text editor, which provides a flexible way to define and change Logo instructions. The main command for starting up the Logo Editor is edit.

How the editor works

When you call the Editor, Logo changes the screen. The editor uses the entire screen with the header:

PICO LOGO EDITOR

centred on the top row (the top row is reverse video). The bottom line has centred in reverse video

ESC - ACCEPT BRK - CANCEL

The content you edit is on the 30 lines between the top and bottom rows. There is no prompt character, but the cursor shows where you are typing.

The text that you edit is in an area of memory called a buffer. When you enter the Editor, Logo displays the text from the edit buffer, up to 30 lines per screen.

You can move the cursor anywhere in the text using the cursor control keys described later in this section. You can also delete and insert characters using the appropriate keys.

Each key that you type makes the Editor take some action. Most typewriter characters (letters, numbers, punctuation, and Enter) are simply inserted into the buffer at the place marked on the screen by the cursor.

When you press Enter, the cursor (and any text that comes after it) moves to the next line, ready for you to continue typing.

You can have more characters on a line of text than fit across the screen. When you get to the end of the line on the screen, just continue typing without pressing Enter. The screen will scroll horizontally to show the rest of the line.

The Editor has an auxiliary line buffer called the copy buffer. You can use it to move text in a procedure or to repeat them in different places. The copy buffer can hold a limited number of characters. While this is true for the copy buffer, the length of a line is limited only by the length of the edit buffer.

Editing actions

When you are in the editor, you can use the following editing keys:

Cursor motion

  • - moves the cursor one character to the left
  • - moves the cursor one character to the right
  • - moves the cursor up to the previous line at the same column
  • - moves the cursor down to the next line at the same column
  • Home - toggles the cursor between the first non-whitespace character and the beginning of the line
  • End - moves the cursor to the end of the line
  • Shift - moves the cursor to the previous page
  • Shift - moves the cursor to the next page

The cursor will not move if that position is not valid.

Inserting and deleting

  • Enter - creates a new line at the current cursor position and moves the cursor (and any text that comes after it) to the new line
  • ←Back - erases the character to the left of the cursor
  • Del - erases the character at the cursor position
  • Tab - inserts spaces until the next tab stop (tab stops are every 2 columns)
  • Ctrl F - starts incremental search (finds text)
  • Ctrl X or Ctrl T - erases (or takes) the current line and stores the text in the copy buffer, including the new line
  • Ctrl C or Ctrl Y - copies (or yanks) the current line and stores the text in the copy buffer, including the new line
  • Ctrl V or Ctrl P - inserts (or pastes) the text in the copy buffer at the cursor position

Block editing

Selected text is between the start anchor and the cursor and is shown in reverse video. The character at the cursor is not included in the selection. Ctrl B sets the start anchor at the cursor position. Pressing Ctrl B when the start anchor is set removes the start anchor and cancels the selection. The cursor motion keys are used to select text when the start anchor is set.

  • Del or ←Back - erases the selected text without storing the text in the copy buffer
  • Ctrl X or Ctrl T - erases (or takes) the selected text and stores the text in the copy buffer
  • Ctrl C or Ctrl Y - copies (or yanks) the selected text and stores the text in the copy buffer
  • Ctrl V or Ctrl P - replaces (or pastes over) the selected text with the text in the copy buffer.
  • Ctrl , - decreases the indent of the block by one tab stop
  • Ctrl . - increases the indent of the block by one tab stop

Typing any other key (except Esc or Brk) is ignored while the selection of text is active.

Incremental search finds and highlights text matches in real time as you type each letter. Ctrl F starts incremental search. In this mode, typing characters will cause the editor to jump to the first match of the accumulated match text starting at the current cursor position. The match (if found) is selected (block editing). Pressing will jump to the next match of your typed phrase, and will jump to the previous match of your typed phrase, both cycling through all occurrences. Pressing ←Back removes the last letter to widen the search back out.

Matching ignores the difference between upper and lower case, so fd finds FD. When the typed phrase matches nowhere in the buffer, nothing is selected and the cursor stays at the last match found.

During incremental search, the bottom line now displays (left justified in reverse video) Search: followed by the characters in the search text. A maximum of 32 characters may be used to match text.

Pressing Esc leaves incremental search and any selected text remains selected. Pressing Brk leaves the Editor, cancelling your changes as usual.

Replacing text

Ctrl R, during an incremental search, replaces every match of the search text. The bottom line changes to Replace: and the text you type after it is what each match is replaced with, up to 32 characters. The replacement is used exactly as typed, whatever the case of the text it matched, so searching for fd and replacing with forward changes FD to forward as well.

While typing the replacement, and move the cursor through it, ←Back erases the character to the left of the cursor and Del erases the character at the cursor. Tab and the other non-printable keys are ignored.

Pressing Enter replaces every match in the buffer and leaves incremental search. An empty replacement is allowed and erases every match. Nothing is replaced if the result would not fit in the Editor's buffer.

Pressing Esc cancels the replacement and returns to the incremental search, where the match found so far is still selected. Pressing Brk leaves the Editor, cancelling your changes as usual.

Viewing screens

F3 lets you see temporarily the graphics screen and its most recent contents. F1 restores the screen back to the Editor so you can pick up where you left off.

Exiting the editor

When you exit from the Editor using Esc, Logo reads each line in the edit buffer as if you had typed it directly from top level.

If the instructions in the edit buffer define a procedure (that is, if there is a title line to ... that starts the definition), Logo behaves as though you had typed the definition of the procedure using to. If the buffer contains a procedure definition, but there is no end instruction at the end of the buffer, Logo helps out by ending the definition for you.

If there are Logo instructions on lines in the edit buffer that are part of the definition of a procedure, Logo caries them out when you exit the editor. Logo will not carry out any graphics commands or editing commands.

In the Editor, you may define more than one procedure at a time as long as each procedure is terminated by end.

Exiting the editor using Brk, Logo does not read any lines in the edit buffer. If you were defining a procedure, the definition will be the same before you started editing.

edit (ed)

edit name
edit namelist
ed name
ed namelist
(edit)
(ed)

command

Starts the Pico Logo Editor. Starts the Logo Editor with the procedure named name (or procedures in the list namelist) and their definitions in it. This is the same output as pops.

If edit does not have an input the current contents of the buffer are used.

Example:

?to rink  pr [Zamboni break]  end
?edit "rink
; Opens the editor with the rink procedure

edall

edall

command

Starts the Pico Logo Editor with all procedures and variables. Procedures are formatted using to/end syntax, variables as make commands, and property lists as pprop commands. This is the same output as poall. The format ensures that when you exit the editor, all definitions can be re-executed to recreate the workspace state.

Example:

?make "snack "butter\ tart
?to pack  pr [Packed:] pr :snack  end
?edall
; Opens the editor with all procedures and variables

edn

edn name
edn namelist

command

Stands for edit name (name must be quoted). Starts the Logo Editor with the variable named name (or variables in the list namelist) and their values in it. This is the same output as pon. When you exit the editor the make are run, so whatever variables and values have been changed in the editor are changed in Logo.

Example:

?make "snack "ketchup\ chips
?edn "snack
; Opens the editor with: make "snack "ketchup\ chips

edns

edns

command

Stands for edit names. Starts the Logo Editor with all the names and their values in it. This is the same output as pons. When you exit the editor the make are run, so whatever variables and values have been changed in the editor are changed in Logo.

Example:

?make "snack "ketchup\ chips
?make "temp -17
?edns
; Opens the editor with all variables

to

to name input1 input2 ...

command

to tells Logo you are defining a procedure called name with the inputs (if any) as indicated. From top level, the prompt character changes from ? to > to remind you that you are defining a procedure. While you are defining a procedure, Logo does not carry out the instructions.

You need not put a quotation mark before name because TO puts one there automatically.

To complete the procedure and return Logo to top level, type the word end as the last word of the procedure. The special word end must be the last word on its line; it is usually on a line of its own, but a short procedure may be written entirely on one line, as in to rink pr [Zamboni break] end.

If you change your mind while defining a procedure with to, press Brk to stop the definition.

Example:

?to square :size
>repeat 4 [fd :size rt 90]
>end

end

end

command

end is necessary, when you are using to, to tell Logo that you are done defining a procedure. It must be the last word on its line, so that end inside a list (pr [the end]) or after a quotation mark (pr "end) is an ordinary word. end also must be used to separate procedures when defining multiple procedures in the Logo Editor.

Example:

?to announce :thing
>pr se [Freshly zambonied] :thing
>end
?announce "ice
Freshly zambonied ice

===

Turtle Graphics

Pico Logo has two kinds of screens: the graphics screen and the text screen. The commands fullscreen, splitscreen, and textscreen allow you to switch between the two kinds of screens, and the F1, F2, and F3 keys do the same from the keyboard. Only those commands and keys change which screen you see: drawing while the text screen is up is not an error, and it does not switch screens. The turtle goes on drawing on the graphics screen, and your picture is waiting for you the next time you look at it.

The screen limits are 320 turtle steps high and 320 steps wide. Hence, when using Cartesian coordinates (as in setpos), you reach the edge of the screen when the y-coordinate is 160 (top) or -159 (bottom) and the x-coordinate is -159 (left edge) or 160 (right edge).

back (bk)

back distance
bk distance

command

The back command moves the turtle distance steps back. Its heading does not change. If the pen is down, Logo draws a line the specified distance.

Example:

?bk 50

clearscreen (cs)

clearscreen
cs

command

clearscreen erases the graphics screen, puts the turtle in the center of the screen, and sets the turtle's heading too (north). The center of the screen is position [0 0] and is called the home position.

Example:

?cs

forward (fd)

forward distance
fd distance

command

forward moves the turtle forward distance steps in the direction in which it is heading. If the pen is down, Logo draws a line the specified distance.

Example:

; Draw a maple-leaf stem
?fd 100

getsh

getsh shapenumber

operation

Outputs a list of 16 numbers representing the turtle shape shapenumber (an integer between 1 and 15). Note that shape number cannot be 0. Each shape consists of 8 columns by 16 rows. Each element in the list is the sum of the bit values for a row in the shape.

The first element of the list is the first row of the shape. If the whole row is filled in, the number is 255. If the row is empty, the number is 0. If only the right-most position is filled, the number is 1. If only the fifth position is filled, the number is 16.

>getsh 3
24 60 126 90 90 90 126 231 189 189 165 36 36 36 102 0

hideturtle (ht)

hideturtle
ht

command

hideturtle makes the turtle invisible. (The turtle draws faster when it is hidden.)

Example:

?ht
?repeat 4 [fd 50 rt 90]

home

home

command

The home command moves the turtle to the center of the screen and sets its heading to 0. If the pen is down, Logo draws a line to the new position. The home command is equivalent to

setpos [0 0]
setheading 0

left (lt)

left degrees
lt degrees

command

The left command turns the turtle left (counterclockwise) the specified number of degrees. The number of degrees must not be greater than approximately 3.4e38, the maximum value for a (32-bit) IEEE 754 floating point number.

Example:

; Turn to face west
?lt 90

putsh

putsh shapenumber shapespec

command

Gives shapenumber the specified shapespec as its shape. The output of getsh can be the input of putsh. shapenumber is in the range of 1 to 15. Shape 0 cannot be changed. putsh defines the slot's bitmap shape, and removes any full-colour picture captured into the slot with snapsh.

>putsh 1 [8 28 28 8 93 127 62 127 127 127 127 127 62 62 93 65]
>setsh 1

See getsh to learn about shapespec.

right (rt)

right degrees
rt degrees

command

The right command turns the turtle right (clockwise) the specified number of degrees. The number of degrees must not be greater than than approximately 3.4e38, the maximum value for a (32-bit) IEEE 754 floating point number.

Example:

; Draw an equilateral triangle
?repeat 3 [fd 80 rt 120]

setheading (seth)

setheading degrees
seth degrees

command

setheading turns the turtle so that it is heading in the direction degrees, which can be any decimal number less than than approximately 3.4e38, the maximum value for a (32-bit) IEEE 754 floating point number. Positive numbers are clockwise from north, negative numbers are counterclockwise from north. Note that right and left do relative motion, but setheading does absolute motion.

Example:

; Face west (towards British Columbia from Ontario)
?seth 270
?fd 100

setpos

setpos [xcor ycor] (setpos xcor ycor)

command

The setpos (for set position) command moves the turtle to the indicated coordinates. If the pen is down, Logo draws a line to the new position.

Example:

; Move to the top of the screen (representing north)
?pu
?setpos [0 100]
?pd

setsh

setsh shapenumber

command

Stands for set shape. Sets the shape of each turtle you are talking to. shapenumber 0 is the line-drawn turtle; slots 1 to 15 hold shapes you define - either a bitmap from putsh or a full-colour picture captured with snapsh; setsh wears whichever the slot holds. Shapes 1 through 15 are blank when Logo starts.

Whatever the slot holds, the shape is centred on the turtle's position, and setrot does not change that. Two turtles at the same position line up whichever rotation styles they wear.

Example:

?setsh 1

setx

setx xcor

command

setx moves the turtle horizontally to a point with x-coordinate xcor. The y-coordinate is unchanged. If the pen is down, Logo draws a line to the new position.

Example:

; Draw a horizontal line across the centre of the screen
?setpos [-159 0]
?pd
?setx 160

sety

sety ycor

command

sety moves the turtle vertically to a point with y-coordinate ycor. The x-coordinate is unchanged. If the pen is down, Logo draws a line to the new position.

Example:

; Draw a vertical line (like a flagpole)
?setpos [0 -100]
?pd
?sety 100

shape

shape

operation

Output the shape number of the current turtle. The normal turtle shape is 0.

Example:

?pr shape
0

showturtle (st)

showturtle
st

command

showturtle makes the turtle visible. See hideturtle.

Example:

?ht
?repeat 4 [fd 50 rt 90]
?st

heading

heading

operation

heading outputs the turtle's heading, a decimal number greater than or equal to 0 and less than 360. Logo follows the compass system where north is a heading of 0 degrees, east 90, south 180, and west 270. When you start up Logo, the turtle has a heading of 0 (straight up).

Example:

?seth 90
?pr heading
90

pos

pos

operation

pos (for position) outputs the coordinates of the current position of the turtle in the form of a list [xcor ycor]. When you start up Logo, the turtle is at [0 0], the centre of the turtle field.

Example:

?setpos [50 80]
?show pos
[50 80]

shown? (shownp)

shown?
shownp

operation

shown? outputs true if the turtle is not hidden, false otherwise.

Example:

?pr shown?
true
?ht
?pr shown?
false

towards

towards [xcor ycor]

operation

towards outputs a heading that would make the turtle face in the direction indicated by [xcor ycor].

Example:

; What heading points from home toward the west coast ferry?
?home
?pr towards [-100 0]
270

xcor

xcor

operation

xcor outputs the x-coordinate of the current position of the turtle.

Example:

?setpos [45 80]
?pr xcor
45

ycor

ycor

operation

ycor outputs the y-coordinate of the current position of the turtle.

Example:

?setpos [45 80]
?pr ycor
80

arc

arc angle radius

command

The arc command draws an arc of a circle centred on the turtle, with the given radius. The arc starts at the turtle's heading and extends clockwise through angle degrees (counterclockwise if angle is negative). The turtle itself does not move.

The arc is drawn with the current pen state and colour: with the pen up nothing is drawn, and penerase and penreverse work as they do for forward. An angle beyond 360 draws one full circle. In fence mode, an arc that would cross the edge of the screen draws up to the boundary and then reports "Turtle out of bounds".

Example:

; Draw a face: head, two eyes, and a smile
?arc 360 80
?pu setpos [-30 30] pd arc 360 8
?pu setpos [30 30] pd arc 360 8
?pu setpos [0 10] pd seth 90 arc 180 40

clean

clean

operation

The clean command erases the graphics screen but doesn't affect the turtle.

Example:

?repeat 4 [fd 60 rt 90]
?clean

dot

dot [xcor ycor]

command

The dot command puts a dot of the current pen colour at the specified coordinates, without moving the turtle. It does not draw a line, even if the pen is down.

Example:

; Mark the centre of the screen (home position)
?dot [0 0]

fence

fence

command

The fence command fences in the turtle within the edges of the screen. If you try to move the turtle beyond the edges of the screen, an error, "Turtle out of bounds" occurs and the turtle does not move. If the turtle is already out of bounds, Logo repositions it at its home position [0 0].

See window and wrap.

Example:

?fence
?fd 1000
Turtle out of bounds

fill

fill

command

The fill command fills the shape outlined by the current pen colour with the current pen colour. If the turtle is not enclosed, the background is filled with the current pen colour. Logo ignores lines of colours other than the current pen colour when determining what to fill.

Example:

; Draw and fill a square (like a red maple leaf background)
?setpc 4
?repeat 4 [fd 60 rt 90]
?fill

pendown (pd)

pendown
pd

command

The pendown command puts the turtle's pen down. When the turtle moves, it draws lines in the current pen colour. When you start up Logo, the pen is down.

Example:

?pu
?setpos [0 0]
?pd
?fd 80

penerase (pe)

penerase
pe

command

penerase puts the turtle's eraser down. When the turtle moves, it erases lines it passes over. To take away the eraser, use either pendown or penup.

Example:

; Draw then erase part of a line
?fd 80
?pe
?bk 40
?pd

penreverse (px)

penreverse
px

command

penreverse puts the reversing pen down. When the turtle moves, it tries to interchange the pen colour and background colour, drawing where there aren't lines and erasing where there are. The exact effect of this reversal is complex; what it looks like on the screen depends on the pen colour, background colour, and whether lines are horizontal or vertical. The best results are on a black background.

Example:

?px
?repeat 4 [fd 60 rt 90]
?pd

penup (pu)

penup
pu

command

The penup command lifts the pen up: when the turtle moves, it does not draw lines. The turtle cannot draw until the pen is put down again.

Example:

; Reposition turtle without drawing
?pu
?setpos [50 50]
?pd

setbg (setbackground)

setbg colournumber
setbackground colournumber

command

The setbg (for set background) command sets the background colour to the colour represented by colournumber, where colournumber is a value between 0 and 254. The backgound colour is used for the background of the full graphics screen and not for the text screen. To set the background colour for text see settextcolor.

The background colour number is 255. The default background colour number is 0.

See Colours for the default palette.

Example:

; Set a red background for the stop sign you nearly missed
?setbg 4

setpc (setpencolor)

setpc colournumber

command

The setpc (for set pencolor) command sets the color of the pen to colourumber, where colournumber is a value between 0 and 255.

See Colours for the default palette.

Example:

; Draw in red (maple leaf red)
?setpc 4
?repeat 4 [fd 60 rt 90]

setpensize

setpensize size

command

The setpensize command sets the width of the pen, in pixels, where size is a whole number of 1 or more. The value is rounded to the nearest whole number and clamped to a maximum of 32. When you start up Logo, the pen size is 1.

A pen wider than one pixel draws by stamping a filled disc at each point along the line, so lines have the same apparent width at every angle and round ends. The reversing pen (penreverse) always draws one pixel wide, regardless of the pen size.

Example:

; Draw a thick square
?setpensize 5
?repeat 4 [fd 60 rt 90]

settextcolor (settc)

settextcolor [foreground background]
settc [foreground background]

command

The settextcolor command sets the foreground and background colours for text. The input is a list of two colour numbers, where each colour number is a value between 0 and 15.

See Colours for the default palette.

Example:

; White text on red background
?settc [15 4]
?pr [Depot open at dawn]

setpalette

setpalette colournumber list

command

setpalette sets the actual colour corresponding to a given colournumber and colournumber must be an integer greater than or equal to 0. The second input is a list of three nonnegative numbers less than 256 specifying the saturation of red, green, and blue in the desired colour.

See Colours for the default palette.

Example:

; Define colour 16 as maple-leaf red
?setpalette 16 [196 30 58]
?setpc 16

palette

palette colournumber

operation

palette outputs a list of three nonnegative numbers less than 256 specifying the saturation of red, green, and blue in the colour associated with the given colour number.

Colour numbers 254 and 255 are the foreground text and background colours.

Example:

?show palette 4
[170 0 0]

restorepalette

restorepalette

command

Restores the palette's default colours. This command only restores colour numbers 0 through 127.

Example:

?setpalette 4 [255 0 0]
?restorepalette

window

window

command

The window command makes the turtle field unbounded; what you see is a portion of the turtle field as if looking through a small window around the centre of the screen. When the turtle moves beyond the visible bounds of the screen, it continues to move but can't be seen: The screen is 320 turtle steps high and 320 steps wide. The entire turtle field is 32,768 steps high and 32,768 steps wide.

Changing window to fence or wrap when the turtle is off the screen sends the turtle to its home position [0 0].

See fence and wrap.

Example:

; Allow the turtle to wander off screen
?window
?fd 500

wrap

wrap

command

The wrap command makes the turtle field wrap around the edges of the screen: if the turtle moves beyond one edge of the screen, it continues from the opposite edge. The turtle never leaves the visible bounds of the screen; when it tries to, it wraps around to the other side.

See fence and window.

Example:

; The turtle wraps around from right to left edge
?wrap
?fd 1000

background (bg)

background
bg

operation

background outputs a number representing the colour of the background and is a value between 0 and 255.

See Colours for the default palette.

Example:

?setbg 4
?pr background
4

dot? (dotp)

dot? [xcor ycor]
dotp [xcor ycor]

operation

The dot? operation outputs true if there is a dot on the screen at the indicated coordinates. If there is no dot, dot? outputs false.

Example:

?dot [0 0]
?pr dot? [0 0]
true

pen

pen

operation

pen outputs the current state of the turtle's pen. The states are pendown, penerase, penup, and penreverse. When the turtle first starts up, pen outputs pendown.

Example:

?pr pen
pendown
?pu
?pr pen
penup

pencolor (pc)

pencolor
pc

operation

pencolor outputs a number representing the current colour of the pen.

See Colours for the default palette.

Example:

?setpc 4
?pr pencolor
4

pensize

pensize

operation

pensize outputs a number representing the current width of the pen, in pixels. When the turtle first starts up, pensize outputs 1.

Example:

?setpensize 5
?pr pensize
5

textcolor (tc)

textcolor
tc

operation

textcolor outputs a list of two colour numbers representing the foreground and background colours for text. Each colour number is a value between 0 and 15.

See Colours for the default palette.

Example:

?settc [15 4]
?show textcolor
[15 4]

setmag

setmag magnification

command

Stands for set magnification. setmag 2 draws the turtle you are talking to at double size; setmag 1 returns it to normal. Magnification applies to the turtle's appearance on screen - the line-drawn turtle, bitmap shapes, and captured colour shapes alike - and to stamp. It does not change how far the turtle moves. The drawn turtle is limited to 32 by 32 pixels, so shapes larger than 16 by 16 always appear at normal size.

Example:

?tell 1 st setmag 2   ; turtle 1 appears double size

setrot

setrot style

command

Stands for set rotation style. Chooses how the turtle's shape follows its heading. The style is one of three words:

  • "fixed - the shape never rotates (how shapes behaved on period machines; the default).
  • "full - the shape rotates smoothly to point along the heading.
  • "flip - the shape mirrors left or right depending on which way the turtle faces; most game characters are drawn side-on, and this makes them walk both directions with one picture.

The rotation style applies to bitmap and captured colour shapes; shape 0, the line-drawn turtle, always rotates. Shapes larger than about 22 pixels may lose their corners at diagonal headings with "full, since the drawn turtle is limited to 32 by 32 pixels.

Example:

?setsh 1 setrot "flip
?seth 90 fd 40      ; facing east: shape as drawn
?seth 270 fd 40     ; facing west: shape mirrored

snapsh

snapsh shapenumber width height

command

Stands for snap shape. snapsh captures the rectangle of the graphics screen centred on the turtle - width by height pixels, each from 8 to 32 - and stores it as a full-colour shape in slot shapenumber (1 to 15). Background pixels become transparent, so the captured image keeps its outline when worn as a shape or placed with stamp. Draw a picture with the pen you already know, pick it up with snapsh, and wear it with setsh.

A full-colour shape replaces the slot's putsh bitmap on screen until you define a new bitmap with putsh, which removes the captured image. When you are talking to several turtles, snapsh captures around the lowest-numbered one. Colour shapes are stored in a fixed memory pool; if the pool is full, Logo says it is out of space.

Example:

?repeat 4 [fd 12 rt 90]     ; draw a small box
?fill
?snapsh 1 16 16             ; capture it as shape 1
?cs setsh 1                 ; wear it

stamp

stamp

command

stamp copies the turtle's current shape into the picture at the turtle's position, exactly as it appears on screen. The turtle does not move, and the stamped image becomes part of the drawing - it stays when the turtle walks away, and savepic saves it. Use it for scenery, repeated decorations, or particle trails. Each turtle you are talking to stamps its own shape.

Example:

?setsh 1
?repeat 6 [stamp fd 30]     ; a trail of shape 1

write

write object

command

write draws object as text on the graphics screen at the turtle's position, in the current pen colour. The text is always upright and reads left to right: it begins at the turtle's x and is centred vertically on the turtle's y, so the turtle sits at the middle of the first letter's left edge. The turtle does not move and its heading is ignored. The letters become part of the drawing: they stay when the turtle walks away, and savepic saves them. object is written the same way print writes it, so a list loses its outer brackets and numbers appear in their usual form. Each turtle you are talking to writes at its own position.

Example:

?setpc 2
?write [Score: 100]        ; label the picture
?pu setxy 0 60 pd
?write count [a b c]       ; writes 3

tell

tell turtlenumber
tell turtlenumberlist

command

Pico Logo has eight turtles, numbered 0 to 7. tell chooses which of them your commands talk to. After tell 3, turtle commands such as fd and rt move turtle 3; after tell [0 1 2], each command applies to turtles 0, 1, and 2 in that order. Operations such as pos and heading answer for the lowest-numbered turtle you are talking to. Duplicate numbers are ignored, and a number outside 0 to 7 causes an error.

When Logo starts, and after clearscreen, you are talking to turtle 0 only - programs written for one turtle work unchanged. Turtles 1 to 7 start hidden at the home position; use showturtle to reveal them. When turtles overlap on the screen, the lower-numbered turtle appears on top.

Because tell accepts a list, you can name a group with a variable: make "flock [1 2 3] then tell :flock.

Example:

?tell [0 1]
?setsh 0
?st
?fd 40          ; both turtles move
?tell 1
?rt 90          ; only turtle 1 turns

ask

ask turtlenumber commandlist
ask turtlenumberlist commandlist

command or operation

ask runs commandlist with your commands temporarily redirected to the named turtle or turtles, then goes back to talking to the turtles you had before - even if the list stops with an error. It is the quick way to give one turtle an instruction without changing who you are talking to. Like run, if commandlist is an operation, ask outputs whatever it outputs - handy for reading one turtle's state (ask 2 [xcor]) without changing who you are talking to.

Example:

?tell [0 1 2]
?ask 1 [fd 20]      ; only turtle 1 moves
?fd 10              ; turtles 0, 1 and 2 move
?pr ask 1 [xcor]    ; read turtle 1's x without retelling
20

each

each commandlist

command

each runs commandlist once for every turtle you are talking to, in ascending order, talking to just that one turtle each time. Inside the list, who is the current turtle's number, so each turtle can behave differently.

Example:

?tell [0 1 2 3]
?each [seth who * 90 fd 50]   ; four turtles walk in four directions

who

who

operation

who outputs the turtle number you are talking to, or a list of numbers when you are talking to more than one turtle. Inside each, who is always the single turtle currently being addressed.

Example:

?tell [2 5]
?show who
[2 5]
?each [pr who]
2
5

touching? (touchingp)

touching? turtlenumber turtlenumber

operation

touching? outputs true when the two named turtles overlap on the screen and false otherwise. The test is exact to the pixel: it compares the turtles' rendered shapes - including any rotation and magnification - not just the squares that hold them, so two turtles report a touch only when their actual glyphs meet. Both turtles must be shown; a hidden turtle never touches anything. In wrap mode a turtle that straddles an edge is tested on both sides, so contact across the screen edge counts.

Example:

?tell [0 1]
?st
?ask 1 [setpos [10 0]]
?if touching? 0 1 [pr [crash!]]

over? (overp)

over? colour

operation

over? outputs true when any part of the turtle's shape lies over a canvas pixel drawn in palette slot colour, and false otherwise. It senses the drawing - lines, dots, fills and stamp marks - not other turtles, which are never part of the canvas. When you are talking to more than one turtle, over? answers for the lowest-numbered one; address a specific turtle with ask. Unlike touching?, over? reports for a hidden turtle too.

Example:

?setpc 12  fd 50  bk 50     ; draw a line in colour 12
?if over? 12 [pr [on the wall]]

colourunder (colorunder)

colourunder

operation

colourunder outputs the palette slot of the canvas pixel directly beneath the turtle's position. Like over? it sees only the drawing, never other turtles, and answers for the lowest-numbered turtle you are talking to. Where nothing has been drawn it outputs the background slot.

Example:

?setpc 9  fill                ; flood the area under the turtle
?pr colourunder
9

distance

distance turtlenumber

operation

distance outputs the straight-line distance, in turtle steps, from the turtle you are talking to (the lowest-numbered one) to the turtle named turtlenumber. It complements towards, which gives the heading between points.

Example:

?tell [0 1]
?ask 1 [setpos [30 40]]
?pr distance 1
50

setspeed

setspeed speed

command

setspeed sets how fast each turtle you are talking to moves on its own, in turtle steps per second. Once a turtle has a speed it glides forward along its heading all by itself - drawing with its pen and obeying wrap, window and fence exactly as forward would - while your program does other things or waits at the prompt. A speed of 0 stops the turtle. Autonomous motion is paused by freeze and cleared by clearscreen.

Example:

?setspeed 30      ; glide forward 30 steps every second
?seth 90          ; head east; it keeps moving as you type

speed

speed

operation

speed outputs the autonomous speed, in turtle steps per second, of the turtle you are talking to (the lowest-numbered one). It outputs 0 when the turtle is not moving on its own.

Example:

?setspeed 45
?pr speed
45

setanim

setanim first last interval

command

setanim animates each turtle you are talking to by cycling its shape from first through last (shape numbers 0 to 15), advancing to the next frame every interval milliseconds and looping back to first after last. The frames flip on their own during a program and at the prompt, just like autonomous motion. An interval of 0 stops the animation and leaves the current shape in place. Animation is paused by freeze and cleared by clearscreen.

Example:

?setanim 1 4 100    ; walk cycle: shapes 1..4, 100 ms per frame
?setspeed 20        ; stroll across the screen, legs moving

when

when condition action

command

when arms a demon: a rule that runs action the moment condition becomes true. condition and action are both instruction lists. The condition is checked continually - while your program runs and while you type at the prompt - and its action fires once each time the condition changes from false to true (so a collision fires once on contact, not over and over while the turtles stay touching). Give the same condition an empty action list to disarm that demon; the bare form (when) prints the demons currently armed. Up to eight demons can be armed at once. Demons are paused by freeze, resumed by thaw, and all cleared by cleardemons or when a program stops with an error. clearscreen does not touch them: clearing the screen is a drawing matter, and your demons keep watching.

Example:

?when [touching? 0 1] [pr [crash!] setspeed 0]
?when [over? 12] [seth heading + 90]
?when [key?] []                ; disarm the key demon

cleardemons

cleardemons

command

cleardemons disarms every when demon at once: nothing is watching afterwards. It touches nothing else - the screen is not cleared, turtles gliding under setspeed or animating under setanim carry on, a freeze stays in force until thaw, and an HTTP server keeps listening (though with its serving demon gone, close it with http.unlisten unless you arm another handler). To disarm a single demon, give its condition an empty action list with when.

Example:

?cleardemons     ; nothing is watching now

freeze

freeze

command

freeze suspends all autonomous activity at once: when demons stop firing and turtles given a setspeed or setanim hold their position and frame. Use it to pause a game. Resume everything exactly where it left off with thaw.

Example:

?freeze     ; the action holds still
?thaw       ; and carries on

thaw

thaw

command

thaw resumes the autonomous activity suspended by freeze: when demons are checked again and moving or animating turtles carry on from where they stopped. thaw when nothing is frozen does nothing.

Example:

?freeze
?thaw

===

Tile Maps

A tile is a small square picture - 8 by 8 or 16 by 16 pixels - that you draw once with the pen and then pick up off the screen, the way snapsh picks up a shape. A map is a grid of numbers saying which tile goes in each square of a world. Together they let you build a board far bigger than anything you would want to draw square by square: a maze, a race track, a dungeon floor.

Tiles are cheap in two ways. The bank keeps one copy of each tile no matter how often the map uses it, and the map itself costs one byte per square, so a 64 by 64 world is 4096 bytes - where the same world as a list of lists would use up most of your workspace. And because tile reads a square directly, the map is not just a picture: it is the thing your program asks "what is here?", instead of keeping a second copy of the world in a list.

Building a tile board goes like this:

  1. newtiles chooses the tile size and empties the bank.
  2. Draw each tile with the pen and pick it up with snaptile.
  3. newmap makes the world, and settile fills in the squares.
  4. stampmap paints the whole map onto the graphics screen at once.

After stampmap the board is an ordinary drawing: the turtle's pen draws over it, dot? sees it, and savepic saves it. When one square changes - a treasure is collected, a door opens - change the square with settile and repaint just that square with stamptile.

How big a bank and a map can be depends on your board. On a Pico 2 or Pico 2 W the bank holds 4096 bytes of tiles (63 tiles of 8 by 8, or 15 of 16 by 16) and a map holds 4096 squares - a 64 by 64 world. On a Pimoroni Pico Plus 2 W, which has PSRAM, the bank holds 255 tiles of either size and a map holds 262144 squares - a 512 by 512 world. Asking for more than that says you are out of space. The bank and the map survive clearscreen and an error, so clearing the screen never throws away a world you are in the middle of building.

newtiles

newtiles size

command

newtiles empties the tile bank and says how big its tiles are. size must be 8 or 16, and every tile in the bank is that many pixels square. Use 8 for fine detail such as a maze of narrow corridors, and 16 for chunky scenery such as a road with cars on it.

You can call newtiles again at any time to start over with a different size; the whole bank is emptied, and the map (if you have one) keeps its numbers but now describes squares of the new size. The number of tiles the bank holds depends on the size and on your board: with 8 by 8 tiles a Pico 2 holds 63 of them, and with 16 by 16 tiles it holds 15. A Pimoroni Pico Plus 2 W holds 255 of either.

Example:

?newtiles 8       ; a bank of 8 by 8 tiles

snaptile

snaptile tilenumber

command

Stands for snap tile. snaptile captures the square of the graphics screen centred on the turtle - as many pixels across as newtiles chose - and stores it in the bank as tile tilenumber. Tile numbers start at 1; the largest one depends on your board and the tile size.

Unlike snapsh, nothing becomes transparent: a tile is background, so every pixel is kept exactly as it is on the screen, including the background colour. Draw your tile with the pen, snap it, clear the screen, and draw the next one. When you are talking to several turtles, snaptile captures around the lowest-numbered one.

Tile 0 is not a tile you can capture. It means "nothing here" in a map, and is painted in the background colour.

Example:

?newtiles 8
?repeat 4 [fd 8 rt 90]    ; a small box
?fill
?snaptile 1               ; keep it as tile 1

newmap

newmap columns rows

command

newmap makes a new world columns squares across and rows squares down, with every square set to 0 (nothing). Both numbers must be at least 1, and the number of squares - columns times rows - must fit in your board's map: 4096 squares on a Pico 2 or Pico 2 W, 262144 on a Pimoroni Pico Plus 2 W. A bigger map than that says you are out of space.

The map is a grid of squares, not of pixels. How big it is on the screen depends on the tile size: a 28 by 36 map of 8 by 8 tiles covers 224 by 288 pixels.

Example:

?newmap 28 36     ; a world of 28 x 36 squares

settile

settile column row tilenumber

command

settile puts a tile number into one square of the map. column and row start at 1, like the positions item counts, with column 1 row 1 at the top left. tilenumber is 0 to 255: 0 means "nothing here" and is painted in the background colour, and any other number names a tile in the bank. A number naming a tile you never captured is also painted as background, so you can fill a map in before you finish drawing its tiles.

Changing a square does not change the screen. Repaint it with stamptile, or repaint the whole board with stampmap.

Example:

?settile 3 4 1      ; square (3,4) shows tile 1
?stamptile 3 4      ; and show it now

tile

tile column row

operation

tile outputs the tile number in one square of the map - the number settile put there, or 0 for an empty square. column and row start at 1.

This is how a program asks the world a question. Because the answer comes straight out of the map, it is just as fast in a 512 by 512 world as in a tiny one, and it is always the same world your board was painted from - there is no second copy to keep in step.

Example:

to walkable? :col :row
op (tile :col :row) = 0     ; empty squares can be walked on
end

stampmap

stampmap

command

stampmap paints the whole map onto the graphics screen: every square of the world is drawn with the tile it names, and empty squares are painted in the background colour. It is the fast way to lay down a board - what would be hundreds of Logo commands is one command here.

What stampmap leaves behind is an ordinary drawing. The pen draws over it, dot? sees it, savepic saves it, and clearscreen wipes it (the map itself is not touched, so you can stampmap it again). If you have no map or no tiles yet, stampmap does nothing.

Example:

?stampmap       ; paint the board

stamptile

stamptile column row

command

stamptile repaints one square of the map onto the graphics screen, where stampmap would have put it. It is the repair command: when a square changes during a game - a treasure taken, a wall knocked down, a door opened - change it with settile and then repaint just that square, instead of the whole board.

column and row start at 1. Anything the pen drew over that square is covered up.

Example:

?settile 3 4 0      ; the treasure is collected
?stamptile 3 4      ; wipe it off the board

===

Text and Screen Commands

Your PicoCalc has 32 lines of text on the screen, with 40 characters on each line. You can use the screen entirely for text or entirely for graphics. The PicoCalc also lets you use the top 24 lines (240 turtle units) for graphics and the bottom eight for text at the same time. When you start up Logo, the entire screen is available for text.

There are two ways to change the use of your screen:

  • With regular Logo commands, which you can type at top level or insert within procedures (fullscreen, splitscreen, and textscreen)
  • With special control characters, which are read from the keyboard and obeyed almost immediately (while a procedure continues running); these cannot be placed within procedures (F1–textscreen, F2–splitscreen, and F3–fullscreen).

You always can use the entire text screen and the entire graphics screen at the same time, but you cannot display both at the same time. When you use the fullscreen command, the text screen is still there, but you can't see it until you use textscreen or splitscreen. When you use textscreen, the graphics screen is still there, but you can't see it until you use fullscreen or splitscreen. When you use splitscreen, both screens are still there, but you can only see the top 24 lines of the graphics screen (240 turtle units) and the bottom eight lines of the text screen.

cleartext (ct)

cleartext
ct

command

cleartext clears the entire screen and puts the cursor at the upper-left corner of the text part of the screen. If you have been using the split screen, the cursor is on the eighth line from the bottom.

Example:

?pr [Snow route starts at midnight]
?ct

cursor

cursor

operation

cursor outputs a list of the column and line numbers of the cursor position. The upper-left corner of the screen is [0 0]. The upper-right is [39 0].

See setcursor.

Example:

?setcursor [10 5]
?show cursor
[10 5]

fullscreen (fs)

fullscreen
fs

command

The fullscreen command devotes the entire screen to graphics. Only the turtle field shows; any text you type will be invisible to you, although Logo will still carry out your instructions.

If Logo needs to display an error message while you are using the full graphics screen, Logo splits the screen.

Example:

?fs
?repeat 4 [fd 80 rt 90]
?ts

refresh

refresh

command

refresh presents any pending graphics drawing on the display immediately. Use it in manual refresh mode (see setrefresh) to control exactly when each frame appears - for example, once per pass around a game loop, after all the drawing for that frame is done.

refresh works in either refresh mode and does not change the mode. In automatic mode it is rarely needed, since drawing is presented as it happens.

Example:

?setrefresh "manual
?repeat 100 [fd 2 rt 3.6 refresh]
?setrefresh "auto

refreshmode

refreshmode

operation

refreshmode outputs the word auto, manual or sync, naming the current display refresh policy (see setrefresh).

Example:

?print refreshmode
auto

setcursor

setcursor [columnnumber linenumber]

command

setcursor sets the cursor to the position indicated by columnnumber and linenumber. Lines on the screen are numbered from 0 to 31. Character positions (columns) are numbered from 0 to 39.

Example:

; Position the cursor near the centre of the screen
?setcursor [20 15]
?type "Curling

setrefresh

setrefresh "auto
setrefresh "manual
setrefresh "sync
(setrefresh "sync rate)

command

setrefresh selects how graphics drawing reaches the display.

In auto mode (the default), Logo presents drawing on the display as it happens. In manual mode, drawing accumulates off-screen and nothing appears until you say refresh - useful for building a complex picture that should appear all at once, or for pacing the frames of a game or animation yourself.

sync mode is manual with an even cadence built in for games and animation. Drawing still accumulates off-screen, but each pass of your loop ends with sync instead of refresh: sync presents the frame and then waits until the next frame boundary, so the loop runs at a steady rate (frames per second) no matter how much work any one frame did. Without a rate the default is 30; supply your own with the parenthesised form, for example (setrefresh "sync 25). Pacing to a fixed boundary - rather than sleeping a fixed amount after each frame with wait - is what keeps motion smooth, the way a game locked to the television's vertical blank did.

So that a program cannot leave the screen out of date (or the prompt paced) after it stops, Logo restores auto mode when an error stops your program, when it runs throw "toplevel, or when you clear the screen with cs.

Example:

; Draw a complex scene off-screen, then show it all at once
?setrefresh "manual
?repeat 36 [repeat 8 [fd 40 rt 45] rt 10]
?refresh
?setrefresh "auto

; Run a game loop at a steady 30 frames per second
?setrefresh "sync
?until [key?] [update.world  draw.world  sync]
?setrefresh "auto

sync

sync

command

sync presents any pending graphics drawing on the display (exactly like refresh) and then, in sync refresh mode, waits until the next frame boundary so your loop keeps the steady rate set with setrefresh "sync. Call it once per pass around a game or animation loop, after all the drawing for that frame is done.

Because sync waits for a boundary measured from a fixed cadence - not for a fixed delay after variable work, as wait would - the loop advances at an even rate even when some frames do more work than others, so motion stays smooth. If a frame overruns its budget sync does not wait and does not try to catch up; the loop simply runs late from there.

Outside sync mode (or on a device with no clock) sync just presents the frame and returns at once, so it is a safe drop-in for refresh.

Example:

?setrefresh "sync           ; 30 frames per second
?until [key?] [
?  ask 0 [fd 3]
?  sync
?]
?setrefresh "auto

splitscreen (ss)

splitscreen
ss

command

splitscreen devotes the top 24 lines of the screen to graphics and the bottom eight lines to text.

Example:

?ss
?repeat 4 [fd 80 rt 90]

textscreen (ts)

textscreen
ts

command

textscreen devotes the entire screen to text; the graphics screen is invisible to you until you use splitscreen or fullscreen. A turtle command given while the text screen is up still draws, but it does not bring the graphics screen back.

Example:

?fs
?repeat 4 [fd 80 rt 90]
?ts
?pr [Back to text mode]

===

Words and Lists

This section describes the primitives that work on two types of objects in Logo: words and lists. With the primitives described in this section, you can

  • break words and lists into pieces
  • put words and lists together
  • examine words and lists
  • change the case of words and lists.

butfirst (bf)

butfirst object
bf object

operation

butfirst outputs all but the first element of object. butfirst of the empty word or the empty list is an error.

Examples:

?pr butfirst "hello
ello
?show butfirst [a b c d]
[b c d]

butlast (bl)

butlast object
bl object

operation

butlast outputs all but the last element of object.

Examples:

?pr butlast "windmills
windmill
?show butlast [a b c d]
[a b c]

first

first object

operation

first outputs the first element of object. first of the empty word or the empty list is an error. Note that first of a word is a single character; first of a list can be a word or a list.

Examples:

?pr first "hello
h
?show first [a b c d]
a

replace

replace integer object value

operation

replace returns a new list with the element of object whose position within object corresponds to integer replaced with value. For example, if integer is 3, replace returns a list with the third element in the object replaced with value. Object is a word or a list. An error occurs if integer is greater than the length of object or if object is the empty word or list.

Examples:

?pr replace 2 "dig "u
dug
?show replace 4 [a b c d] "x
[a b c x]
?make "greet "hello
?pr replace 1 :greet uppercase item 1 :greet
Hello

.setfirst

.setfirst list value

command

.setfirst destructively replaces the first member of list with value, changing the list in place instead of returning a new one. List must be a non-empty list. Because lists share structure - butfirst returns the tail of a list without copying it - a cursor obtained with butfirst refers to the same cells as the original, and .setfirst through that cursor is visible in the original. This makes it possible to update one element of a long list without allocating a new list; unlike replace, which builds and returns a fresh list, .setfirst outputs nothing.

The leading dot marks .setfirst as dangerous: overwriting a cell that other structure depends on, or using it to build a circular list, corrupts those references. Prefer replace unless you specifically need in-place mutation.

Examples:

?make "l [a b c]
?.setfirst :l "x
?show :l
[x b c]
?make "flags [1 1 1 1]
?.setfirst (butfirst butfirst :flags) 0
?show :flags
[1 1 0 1]

.setbf

.setbf list value

command

.setbf destructively replaces the butfirst (the tail) of list with value, in place. List must be a non-empty list and value must be a list, since the tail of a list is itself a list. Setting the tail to the empty list truncates list to a single member. Like .setfirst, .setbf outputs nothing and mutates every list that shares the affected cell.

The leading dot marks .setbf as dangerous: pointing the tail back into the same list builds a circular list, which most list operations cannot handle.

Examples:

?make "l [a b c]
?.setbf :l [x y]
?show :l
[a x y]
?.setbf :l []
?show :l
[a]

.setitem

.setitem integer list value

command

.setitem destructively replaces the member of list at position integer (counting from 1) with value, in place - the same result as walking to that member with butfirst and applying .setfirst, but the walk is done for you. An error occurs if integer is less than 1 or greater than the length of list. Unlike replace, which returns a fresh list, .setitem outputs nothing and allocates nothing, so it can update one member of a long list cheaply.

The leading dot marks .setitem as dangerous for the same reason as the other in-place setters: it overwrites a shared cell.

Examples:

?make "l [a b c d]
?.setitem 3 :l "x
?show :l
[a b x d]

item

item integer object

operation

item outputs the element of object whose position within object corresponds to integer. For example, if integer is 3, item outputs the third element in the object. Object is a word or a list. An error occurs if integer is greater than the length of object or if object is the empty word or list.

Examples:

?pr item 4 "windmills
d
?show item 2 [a b c d]
b

last

last object

operation

last outputs the last element of object. last of the empty word or the empty list is an error.

Examples:

?pr last "Maple
e
?show last [a b c d]
d

member

member object1 object2

operation

member outputs the part of object2 in which object1 is the first element. If object1 is not an element of object2, member outputs the empty list or the empty word. This operation is useful for accessing information in a file or for sorting long lists.

Examples:

?show member "b [a b c d]
[b c d]
?pr member "x "example
xample
?show member "x [a b c d]
[]
?pr member ". 3.14159
.14159

pick

pick object

operation

pick outputs a randomly chosen element of object: an element of a list, or a character of a word. An error occurs if object is empty.

Examples:

?pr pick [butter\ tart nanaimo\ bar beavertail]
nanaimo bar
?pr pick "abcdef
d

remdup

remdup object

operation

remdup outputs a copy of object with duplicate members removed: the elements of a list, or the characters of a word. When two or more members are equal, only the last one is kept, so the survivors appear in the order of their final occurrence. As with equal?, words are compared without regard to case.

Examples:

?show remdup [a b a c b]
[a c b]
?pr remdup "mississippi
mspi

remove

remove thing object

operation

remove outputs a copy of object with every member equal to thing removed: the elements of a list, or the characters of a word. Because the members of a word are its characters, thing removes characters only when it is itself a single character. As with equal?, the comparison ignores case.

Examples:

?show remove "b [a b c b d]
[a c d]
?pr remove "l "hello\ world
heo word

reverse

reverse object

operation

reverse outputs object with its elements in the opposite order: the elements of a list, or the characters of a word. Elements that are themselves lists are not reversed internally.

Examples:

?show reverse [a b c d]
[d c b a]
?pr reverse "stressed
desserts
?show reverse [a [b c] d]
[d [b c] a]

shuffle

shuffle object

operation

shuffle outputs object with its elements rearranged in random order: the elements of a list, or the characters of a word. Every element of the input appears exactly once in the output.

Example:

?show shuffle [1 2 3 4 5]
[3 1 5 2 4]

fput

fput object list

operation

The fput (for first put) operation outputs a new list formed by putting object at the beginning of list.

Example:

?show fput "a [b c d]
[a b c d]

list

list object1 object2
(list object1 object2 object3 object4 ...)

operation

The list operation outputs a list whose elements are object1, object2, and so on.

Examples:

?show (list "d "o "g)
[d o g]
? show list "Hello "there
[Hello there]

lput

lput object list

operation

The lput (for last put) operation outputs a new list formed by putting object at the end of list.

Example:

?show lput "d [a b c]
[a b c d]

parse

parse word

operation

parse outputs a list that is obtained from parsing word. parse is useful for converting the output of readword into a list.

Example:

?show parse "a\ b\ c\ d
[a b c d]

When parse tokenizes a word that contains vertical bars (see Vertical Bars), the bars do not appear in the result but the characters between them are tokenized as though they were letters. So a word read by readword that contains |a b| parses into the single word a b.

sentence (se)

sentence object1 object2
(sentence object1 object2 object3 ...)
se object1 object2
(se object1 object2 object3 ...)

operation

sentence outputs a list made up of the contents in its inputs.

Examples:

?show (sentence "a [b c] "d)
[a b c d]
?show se "hello "world
[hello world]

word

word word1 word2
(word word1 word2 word3 ...)

operation

word outputs a word made up of its inputs.

A word normally holds up to 255 characters. On a board with PSRAM (the Pimoroni Pico Plus 2 W) word may build a longer result; on boards without PSRAM a result over 255 characters raises an out-of-space error rather than being truncated.

Examples:

?pr (word "Hello, char 32  "world!)
Hello, world!
?pr word "123 "456
123456
?pr word 10 0 + 1
101

ascii

ascii character

operation

ascii outputs the American Standard Code for Information Interchange (ASCII) code for character. If the input word contains more than one character, ascii uses only its first character. Also see char.

Examples:

?pr ascii "A
65
?pr ascii "z
122

before? (beforep)

before? word1 word2
beforep word1 word2

operation

before? outputs true if word1 comes before word2. To make the comparison, Logo uses the ASCII codes of the characters in the words. Note that all uppercase letters come before all lowercase letters.

Examples:

?pr before? "Apple "Banana
true
?pr before? "apple "Banana
false
?pr before? "Cat "cat
true

char

char integer

operation

The char operation outputs the character whose ASCII code is integer. An error occurs if integer is not the ASCIl code for any character.

Examples:

?pr char 65
A
?pr char 122
z

count

count object

operation

count outputs the number of elements in object, which is a word or a list.

Examples:

?pr count "hello
5
?pr count [a b c d]
4

empty? (emptyp)

empty? object
emptyp object

operation

empty? outputs true if object is the empty word or the empty list; otherwise it outputs false.

Examples:

?pr empty? "
true
?pr empty? []
true
?pr empty? "abc
false
?pr empty? [a b c]
false

equal? (equalp)

equal? object1 object2
equalp object1 object2

operation

equal? outputs true if object1 and object2 are equal numbers, identical words, or identical lists; otherwise equal? outputs false. This operation is equivalent to the equal sign (=).

Words are compared without regard to case, just as Logo treats names: equal? "Hello "hello outputs true. Lists are compared element by element under the same rule. (To compare words by their exact character codes, use before?, which compares ASCII values.)

Examples:

?pr equal? "hello "hello
true
?pr equal? "Hello "hello
true
?pr equal? [a b c] [a b c]
true
?pr equal? 10 10
true
?pr equal? "hello "world
false
?pr equal? [a b c] [a b d]
false
?pr equal? 10 20
false

list? (listp)

list? object
listp object

operation

list? outputs true if object is a list; otherwise it outputs false.

Examples:

?pr list? [a b c]
true
?pr list? "hello
false
?pr list? 123
false

member? (memberp)

member? object1 object2
memberp object1 object2

operation

member? outputs true if object1 is an element of object2; otherwise it outputs false.

Examples:

?pr member? "b [a b c d]
true
?pr member? "b "example
false
?pr member? ". 3.14159
true

number? (numberp)

number? object
numberp object

operation

number? outputs true if object is a number; otherwise it outputs false.

Examples:

?pr number? 123
true
?pr number? "hello
false
?pr number? [a b c]
false

word? (wordp)

word? object
wordp object

operation

word? outputs true if object is a word; otherwise it outputs false. A self-quoted number is word.

Examples:

?pr word? "hello
true
?pr word? 123
true
?pr word? [a b c]
false

lowercase

lowercase word

operation

lowercase outputs word in all lowercase letters.

Examples:

?pr lowercase "HelloWorld
helloworld
?pr lowercase "AB123
ab123

uppercase

uppercase word

operation

uppercase outputs word in all uppercase letters.

Examples:

?pr uppercase "HelloWorld
HELLOWORLD
?pr uppercase "ab123
AB123

===

Variables

This section gives you some general information about how Logo uses variables and then provides descriptions of the primitives that you use with variables.

local

local name
local list

command

The local command makes its input(s) local to the procedure within which the local occurs. A local variable is accessible only to that procedure and to procedures it calls; in this regard it resembles inputs to the procedure.

Example:

?to greet
>local "snack
>make "snack "butter\ tart
>pr se [Saved for later:] :snack
>end
?greet
Saved for later: butter tart
?pr name? "snack
false

localmake

localmake name object

command

The localmake command makes name local to the procedure within which it occurs and gives it the value object, in one step. It is equivalent to local "name followed by make "name object.

Example:

?to greet
>localmake "snack "butter\ tart
>pr se [Saved for later:] :snack
>end
?greet
Saved for later: butter tart
?pr name? "snack
false

make

make name object

command

The make command puts object in name's container, that is, it gives the variable name the value object.

Example:

?make "team "house\ league
?pr :team
house league

name

name object name

command

The name command puts object in name's container, that is, it gives the variable name the value object.

name is equivalent to make with the order of the inputs reversed. Thus name "welder "job has the same effect as make "job "welder.

Example:

?name "double\ double "order
?pr :order
double double

name? (namep)

name? word
namep word

operation

name? outputs true if word has a value, that is, if :word exists; it outputs false otherwise.

Example:

?make "permit "yes
?pr name? "permit
true
?pr name? "ticket
false

thing

thing name

operation

thing outputs the thing in the container name, that is, the value of the variable name. thing "any is equivalent to :any.

Example:

?make "forecast "flurries
?pr thing "forecast
flurries
?pr :forecast
flurries

===

Arithmetic Operations

This section presents all the Logo operations that manipulate numbers. Logo has two kinds of notation for expressing arithmetic operations: prefix notation and infix notation. Prefix notation means that the name of the procedure comes before its inputs. With infix notation, the name of the procedure goes between its inputs, not before them.

This chapter contains

  • a general introduction to Logo's arithmetic operations
  • descriptions of the prefix-form operations
  • descriptions of the infix-form operations.

abs

abs number

operation

Outputs the absolute number. If number less than zero the negative of number is returned.

Example:

; Absolute value of a wind-chill complaint
?pr abs -40
40

arctan

arctan number
(arctan x y)

operation

With one input, outputs the arctangent of number in degrees.

With two inputs, (arctan x y) outputs the arctangent of y/x in degrees, using the signs of both inputs to place the result in the full range from -180 to 180. Unlike the one-input form, it is defined when x is zero.

Examples:

?pr arctan 1
45
?pr (arctan -1 1)
135

cos

cos number

operation

Outputs the cosine of number in degrees.

Examples:

?pr cos 0
1
?pr cos 60
0.5

difference

difference number1 number2

operation

Outputs number2 subtracted from number1.

Example:

; Difference between two snow-route ticket numbers
?pr difference 705 416
289

exp

exp exponent

operation

Outputs e raised to the power of exponent.

Example:

?pr exp 1
2.71828

form

form number width decimalplaces

operation

form outputs a word representing number formatted to fit in a field of width characters with decimalplaces digits to the right of the decimal point. If decimalplaces is zero, no decimal point is included. The number is rounded to the specified number of decimal places.

If number is negative, the minus sign takes up one position in the field. If number is too large to fit in the specified width, form outputs a string using the minimum length required for number with decimalplaces.

If width is less than or equal to zero, or if decimalplaces is less than zero, an error occurs.

Examples:

; Format the total after a farmers market pierogi run
?pr word "$ form 1234.56 10 2
$   1234.56
?pr form -17.8 6 1
-17.8

int

int number

operation

Returns the integer part of number; any decimal part is stripped off. No rounding occurs when int is used (contrast this with the round operation described later in this chapter).

Examples:

; Truncate a temperature reading
?pr int -17.8
-17
?pr int 3.9
3

intquotient

intquotient integer1 integer2

operation

intquotient outputs the result of dividing integer1 by integer2, truncated to an integer. An error occurs if integer2 is zero. If either input is a decimal number, it is truncated.

Example:

; How many full four-person curling teams from 18 players?
?pr intquotient 18 4
4

ln

ln number

operation

Outputs natural logarithm of number. An error is returned if number is less than or equal to zero.

Example:

?pr ln 1
0
?pr ln exp 1
1

log

log number

operation

Outputs the base-10 logarithm of number. An error is returned if number is less than or equal to zero.

Example:

?pr log 100
2
?pr log 1000
3

modulo

modulo integer1 integer2

operation

Outputs the remainder of dividing integer1 by integer2 using floor division, so the result takes the sign of integer2. This differs from remainder, whose result takes the sign of integer1. An error is returned if integer2 is zero.

Examples:

?pr modulo -7 3
2
?pr remainder -7 3
-1

product

product number1 number2
(product number1 number2 number3 ...)

operation

Outputs the product of its inputs. It is equivalent to the * infix-form operation. With one input, product outputs its input.

Example:

; Approximate area of a curling sheet in square metres
?pr product 5 45
225

pwr

pwr base exponent

operation

Outputs base raised to the power of exponent.

Example:

?pr pwr 2 10
1024

quotient

quotient number1 number2

operation

Outputs the result of dividing number1 by number2. It is equivalent to the / infix-form operation. Number2 must not be zero. If it is, an error occurs.

Example:

; How many 250 ml cups are in a 1 litre carton of chocolate milk?
?pr quotient 1000 250
4

random

random integer

operation

Outputs a random non-negative integer less than integer. Results come from the device's hardware random source, so every run is different; see rerandom to make them reproducible instead.

Example:

; Pick a random seat row at the community rink
?pr random 20
7

rerandom

rerandom
(rerandom integer)

command

Normally random, pick, and shuffle draw from the device's hardware random source, so their results are unpredictable. rerandom switches them to a reproducible sequence: after running rerandom, the same sequence of results follows every time. Give an integer input to select among different reproducible sequences. The effect lasts until the device is restarted.

rerandom is useful for replaying a game or a bug exactly, and for producing the same results on every device in a classroom.

Example:

?(rerandom 7)
?pr random 100
47
?pr random 100
92
?(rerandom 7)
?pr random 100
47

remainder

remainder integer1 integer2

operation

Outputs the remainder obtained when integer1 is divided by integer2. The remainder is always an integer. If integer1 and integer2 are integers, this is integer1 mod integer2. If integer1 and integer2 are not integers, they are truncated. Integer2 must not be zero. If it is, an error occurs.

Example:

; What is the remainder when dividing 17 by 5?
?pr remainder 17 5
2

round

round number

operation

Outputs number rounded off to the nearest integer. The maximum integer is 2,147,483,647.

Examples:

; Round a temperature in Celsius
?pr round -17.3
-17
?pr round -17.6
-18

sin

sin number

operation

Outputs the sine of number in degrees.

Examples:

?pr sin 30
0.5
?pr sin 90
1

sqrt

sqrt number

operation

Outputs the square root of number. The value number must not be negative or an error will occur.

Example:

; Square root of a 13 by 13 scarf pattern
?pr sqrt 169
13

sum

sum number1 number2
(sum number1 number2 number3 ...)

operation

Outputs the sum of its inputs. sum is equivalent to the + infix-form operation. With one input, sum outputs its input.

Examples:

; Coffee plus a maple dip
?pr sum 2.15 1.45
3.6
?pr (sum 1 2 3 4 5 6 7 8 9 10)
55

tan

tan number

operation

Outputs the tangent of number in degrees.

Example:

?pr tan 45
1

===

Conditionals and Control of Flow

In Logo, the boolean value of true is represented by "true and false is represented by "false.

true

true

operation

Outputs "true. In Logo, boolean truth is represented by the word true.

Example:

?pr true
true
?pr equal? true true
true

false

false

operation

Outputs "false. In Logo, boolean false is represented by the word false.

Example:

?pr false
false
?pr equal? true false
false

;

; comment

command

The semicolon (;) indicates that the rest of the line is a comment. Logo ignores everything on the line after the semicolon. You can use comments to explain what your procedures do.

Example:

to square :number
  ; [This procedure outputs the square of :number]
  output :number * :number
end

if

if predicate list1
(if predicate list1 list2)

command or operation

If predicate is true, Logo runs list1. If predicate is false,Pico Logo runs list2 (if present). In either case, if the selected list outputs something, the if is an operation. If the list outputs nothing, the if is a command.

if as a command:

to decide
  if 0 = random 2 [op "yes]
  op "no
end

to decide
  (if 0 = random 2 [op "yes] [op "no])
end

if as an operation:

to decide
  output (if 0 = random 2 ["yes] ["no])
end

ifelse

ifelse predicate list1 list2

command or operation

ifelse is the same as if except that list2 must be present. If predicate is true, Logo runs list1; if predicate is false, Logo runs list2. In either case, if the selected list outputs something, the ifelse is an operation. If the list outputs nothing, the ifelse is a command.

Example:

to decide
  ifelse 0 = random 2 [op "yes] [op "no]
end

iffalse (iff)

iffalse list
iff list

command

iffalse runs list if the result of the most recent test was false, otherwise it does nothing. Note that if test has not been run in the same procedure or a superprocedure, or from top level, iffalse does nothing.

Example:

?to check.rink :status
>test equal? :status "open
>iftrue [pr [Sharpen your skates]]
>iffalse [pr [Try again after the thaw]]
>end
?check.rink "open
Sharpen your skates
?check.rink "soft
Try again after the thaw

iftrue (ift)

iftrue list
ift list

command

iftrue runs list if the result of the most recent test was true, otherwise it does nothing. Note that if test has not been run in the same procedure or a superprocedure, or from top level, iftrue does nothing.

Example:

?test name? "team
?ift [pr :team]

test

test predicate

command

test remembers whether predicate is true or false for subsequent use by iftrue or iffalse. Each test is local to the procedure in which it occurs.

Example:

?make "score 7
?test :score > 5
?ift [pr [Good draw, skip!]]
Good draw, skip!

ignore

ignore object

command

The ignore command does nothing. It is useful when you want to call a procedure for its side effects only.

Example:

; Call random for a side effect, ignore the result
?ignore random 100

co

co

command

The co (for continue) command resumes running of a procedure after a pause or ESC, continuing from wherever the procedure paused.

Example:

?to survey
>pr [Enter rink snack:]
>pause
>pr [Thank you!]
>end
?survey
Enter rink snack:
survey? pr "fries
fries
survey? co
Thank you!

output (op)

output object
op object

command

The output command is meaningful only when it is within a procedure, not at top level. It makes object the output of your procedure and returns control to the caller. Note that although output is itself a command, the procedure containing it is an operation because it has an output. Compare with stop.

Example:

?to topping :snack
>if equal? :snack "fries [output "gravy]
>if equal? :snack "pierogi [output "sour\ cream]
>if equal? :snack "toast [output "peameal]
>output "Unknown
>end
?pr topping "fries
gravy
?pr topping "pierogi
sour cream

pause

pause

command or operation

The pause command is meaningful only when it is within a procedure, not at top level. It suspends running of the procedure and tells you that you are pausing; you can then type instructions interactively. To indicate that you are in a pause and not a t top level, the prompt character changes to the name of the procedure you were in, followed by a question mark. During a pause, BRK does not work; the only way to return to top level during a pause is to run throw toplevel.

The procedure may be resumed by typing co.

Example:

?to inspect
>pr [Pausing for inspection...]
>pause
>pr [Resumed!]
>end
?inspect
Pausing for inspection...
inspect? pr "debugging
debugging
inspect? co
Resumed!

stop

stop

command

The stop command stops the procedure that is running and returns control to the caller. This command is meaningful only when it is within a procedure-not at top level. Note that a procedure containing stop is a command. Compare stop with output.

Example:

?to check.temp :celsius
>if :celsius > 0 [pr [Above freezing - no parka needed] stop]
>pr [Below freezing - wear your toque!]
>end
?check.temp 5
Above freezing - no parka needed
?check.temp -20
Below freezing - wear your toque!

wait

wait integer

command

wait tells Logo to wait for integer milliseconds.

Example:

; Pause for 1 second between messages
?pr [Kettle on...]
?wait 1000
?pr [Tea is steeped!]

catch

catch name list

command

catch runs list. If a throw name command is called while list is run, control returns to the first statement after the catch. The name is used to match up a throw with a catch. For instance, catch "chair [whatever] catches a throw "chair but not a throw "table.

There is one special case. catch "error catches an error that would otherwise print an error message and return to top level. If an error is caught, the message that Logo would normally print isn't printed. See the explanation of error in this section to find out how to tell what the error was.

Example:

?to safe.divide :a :b
>catch "error [output :a / :b]
>pr se [Error:] item 2 error
>output 0
>end
?pr safe.divide 10 2
5
?pr safe.divide 10 0
Error: Division by zero
0

error

error

operation

error outputs a four-element list containing information about the most recent error that has not had a message printed or output by error. If there was no such error, error outputs the empty list. The elements in the list are

  • a unique number identifying the error
  • a message explaining the error
  • the name of the primitive causing the error, if any
  • the name of the procedure within which the error occurred (the empty list, if top level).

Logo runs throw "error [whenever] an error occurs during the execution of a procedure. Control passes to top level unless a catch "error has been run. When an error is caught in this way, no error message is printed, and you can design your own.

Refer to Error Messages for a complete list of error messages and their meanings.

Example:

?catch "error [make "x 1/0]
?show error
[6 [Division by zero] quotient []]

go

go word

command

The go command transfers control to the instruction following label word in the same procedure.

Example:

?to count.loonies
>make "n 0
>label "loop
>make "n :n + 1
>pr :n
>if :n < 5 [go "loop]
>end
?count.loonies
1
2
3
4
5

label

label word

command

The label command itself does nothing. However, a go word passes control to the instruction following it. Note that word must always be a literal word (that is, it must be preceded by a quotation mark).

Example:

?to countdown
>make "n 10
>label "start
>pr :n
>make "n :n - 1
>if :n > 0 [go "start]
>pr [Zamboni doors closed]
>end

for

for forcontrol instructionlist

command

The first input must be a list containing three or four members: (1) a word, which will be used as the name of a local variable; (2) a word or list that will be evaluated as by RUN to determine a number, the starting value of the variable; (3) a word or list that will be evaluated to determine a number, the limit value of the variable; (4) an optional word or list that will be evaluated to determine the step size. If the fourth member is missing, the step size will be 1 or -1 depending on whether the limit value is greater than or less than the starting value, respectively.

The second input is an instructionlist. The effect of for is to run that instructionlist repeatedly, assigning a new value to the control variable (the one named by the first member of the forcontrol list) each time. First the starting value is assigned to the control variable. Then the value is compared to the limit value. for is complete when the sign of (current - limit) is the same as the sign of the step size. (If no explicit step size is provided, the instructionlist is always run at least once. An explicit step size can lead to a zero-trip for, e.g., for [i 1 0 1] ...). Otherwise, the instructionlist is run, then the step is added to the current value of the control variable and for returns to the comparison step.

? for [i 2 7 1.5] [print :i]
2
3.5
5
6.5
?

do.while

do.while list predicatelist

command

do.while runs list repeatedly as long as predicatelist is true. An error occurs if predicatelist is not true or false. A do.while loop can be exited early by a throw or stop command. list is always run at least once.

Example:

; Count ferry boarding calls
?make "call 1
?do.while [pr se [Call:] :call  make "call :call + 1] [:call <= 3]
Call: 1
Call: 2
Call: 3

while

while predicatelist list

command

while tests predicatelist and, if it is true, runs list. It then repeats this process until predicatelist is false. An error occurs if predicatelist is not true or false. A while loop can be exited early by a throw or stop command. list may not be run at all if predicatelist is initially false.

Example:

; Count days below freezing
?make "temp -17
?make "days 0
?while [:temp < 0] [make "days :days + 1  make "temp :temp + 3]
?pr :days
6

do.until

do.until list predicatelist

command

do.until runs list repeatedly until predicatelist is true. An error occurs if predicatelist is not true or false. A do.until loop can be exited early by a throw or stop command. list is always run at least once.

Example:

; Print ticks until the kettle boils
?make "ticks 0
?do.until [make "ticks :ticks + 1  pr :ticks] [:ticks = 5]
1
2
3
4
5

until

until predicatelist list

command

until tests predicatelist and, if it is false, runs list. It then repeats this process until predicatelist is true. An error occurs if predicatelist is not true or false. An until loop can be exited early by a throw or stop command. list may not be run at all if predicatelist is initially true.

Example:

; Count loonies to ten
?make "score 0
?until [:score = 10] [make "score :score + 1]
?pr :score
10

forever

forever list

command

forever runs list repeatedly until interrupted by Brk, F4 or F9. A forever loop can also be exited by a throw or stop command.

Example:

; Flash a warning until Brk is pressed
?to blink.warning
>forever [pr [Check ice conditions!]  wait 1000]
>end

repeat

repeat integer list

command

repeat runs list integer times. An error occurs if integer is negative can can be interrupted by Brk, F4 or F9. A repeat loop can be exited early by a throw or stop command.

Example:

; Draw a square
?repeat 4 [fd 50 rt 90]

repcount

repcount

operation

recount outputs the repetition count of the innermost current repeat or forever, starting from 1. If no repeat or forever is active, outputs –1.

Example:

; Number three butter tart batches
?repeat 3 [pr se [Batch] repcount]
Batch 1
Batch 2
Batch 3

run

run list

command or operation

The run command runs list as if typed in directly. If list is an operation, then run outputs whatever list outputs.

Example:

?run [pr [Mind the slush]]
Mind the slush
?make "action [pr "sorry]
?run :action
sorry

runresult

runresult list

operation

runresult runs list as if typed in directly, like run, but reports whether it produced a value rather than passing the value along. If list outputs a value, runresult outputs a one-member list containing that value; if list runs a command that outputs nothing, runresult outputs the empty list. It is most useful for running a list whose contents you do not control, where you cannot know in advance whether it will output.

Example:

?show runresult [sum 2 3]
[5]
?show runresult [pr "done]
done
[]

throw

throw name

command

The throw command is meaningful only within the range of the catch command. An error occurs if no corresponding catch name is found. throw toplevel returns control to top level. Contrast with stop.

See catch.

Example:

?to find.snack :list :target
>catch "found [
>  foreach :list [[p]
>    if equal? :p :target [pr se [Found:] :p  throw "found]
>  ]
>  pr [Snack not found]
>]
>end
?find.snack [chips squares nanaimo] "nanaimo
Found: nanaimo

toplevel

toplevel

operation

Outputs "toplevel. throw toplevel to return control to the top level.

Example:

?to emergency.exit
>pr [Returning to top level!]
>throw toplevel
>end

step

step name
step list

command

The step command takes the procedure indicated by name or list as input and lets you run them line by line. step pauses at each line of execution and continues only when you press any key on the keyboard.

Example:

?to greet
>pr [Hello]
>pr [from the rink]
>end
?step "greet
?greet
; Execution pauses after each line, press any key to continue

trace

trace name
trace list

command

The trace command takes the procedures indicated by name or list as input and causes them to print tracing information when executed. It does not interrupt the execution of the procedure, but allows you to see the depth of the procedure stack during execution. trace is useful in understanding recursive procedures or complex programs with many subprocedures.

Example:

?to greet :name
>pr se [Hello] :name
>end
?trace "greet
?greet "Riley
==> greet [Riley]
Hello Riley
<== greet

unstep

unstep name
unstep list

command

unstep restores the procedure(s) indicated by name or list back to their original states. After you step through a procedure (with step), you must use unstep so that it will execute normally again.

Example:

?step "greet
; ... step through greet ...
?unstep "greet
; greet now runs at normal speed again

untrace

untrace name
untrace list

command

untrace stops the tracing of procedure name and causes it to execute normally again.

Example:

?trace "greet
?greet "Casey
==> greet [Casey]
Hello Casey
<== greet
?untrace "greet
?greet "Casey
Hello Casey

===

List Processing

The primitives in this section let you process lists. Each primitive takes either name of the procedure, a lambda expression or procedure text to apply to each element of the list.

For example, if you wanted to concatenate corresponding elements of two lists, you could use the following map command with a named procedure:

?show (map "word [a b c] [d e f])
[ad be cf]

A lambda expression is an anonymous procedure. It is written as a list whose first element is a list of input names (with no colons) and whose remaining elements are the expression for the output. For example, the lambda expression that adds 1 to its input would be written as follows:

[[x] :x + 1]

We could use this lambda expression with map to add 1 to each element of a list:

?show map [[x] :x + 1] [1 2 3]
[2 3 4]

An anonymous procedure is a list whose first element is a list of input names (with no colons) and whose remaining elements are the body of the procedure. This is the list text that is used with define and output bytext. For example, the anonymous procedure that adds two numbers would be written as follows:

[[x y] [output :x + :y ]]

To add the corresponding elements of two lists, we could use this anonymous procedure with map:

?show map [[x y] [ output :x + :y ]] [1 2 3] [4 5 6]
[5 7 9]

The anonymous procedure, while not recommended for complex procedures, can be used, when multiple lines are needed:

[[x y] [(print [x+y=] :x + :y)] [output :x + :y]]

For a more complex example, to calculate the distance between two points in any number of dimensions, we can use map and apply together with lambda expressions:

? show sqrt apply "sum map [[x] pwr :x 2] (map [[a b] :a - :b] [1 2 3] [4 5 6])
5.19615

apply

apply procedure inputlist

command or operation

Runs procedure, providing its inputs with the members of inputlist. The number of members in inputlist must be an acceptable number of inputs for procedure. apply outputs what procedure outputs, if anything.

Examples:

?show apply [[a b c] :a + :b + :c] [1 2 3]
6
?show apply "sum [1 2 3 4]
10

foreach

foreach data procedure
(foreach data1 data2 ... procedure)

command

Evaluates procedure repeatedly, once for each member of the data list. If more than one data list are given, each of them must be the same length. (The data inputs can be words, in which case procedure is evaluated once for each character.)

Each data list provides one input to procedure at each evaluation. Thus, if there are two data lists, procedure must have two inputs; if there are three data lists, procedure must have three inputs; and so on.

Examples:

?foreach [1 2 3] [[i] print :i]
1
2
3
?
?(foreach [1 2 3] [4 5 6] [[a b] print :a + :b])
5
7
9
?

map

map procedure data
(map procedure data1 data2 ...)

operation

map evaluates procedure once for each member of the data list and outputs a object of the results. If more than one data object are given, each of them must be the same length. (The data inputs can be words, in which case procedure is evaluated once for each character.) The output object will be a word if the first data input is a word; otherwise, the output will be a list.

Each data list provides one input to procedure at each evaluation. Thus, if there are two data lists, procedure must have two inputs; if there are three data lists, procedure must have three inputs; and so on.

Examples:

?show map [[x] :x * :x] [1 2 3 4]
[1 4 9 16]
?show (map "sum [1 2 3] [4 5 6])
[5 7 9]
?show map [[x] ascii :x] "hello"
104101108108111
?

map.se

map.se procedure data (map.se procedure data1 data2 ...)

operation

Outputs a list formed by evaluating the procedure repeatedly and concatenating the results using sentence. That is, the members of the output are the members of the results of the evaluations. The output list might, therefore, be of a different length from that of the data input(s). (If the result of an evaluation is the empty list, it contributes nothing to the final output.) The data inputs may be words or lists.

Each data list provides one input to procedure at each evaluation. Thus, if there are two data lists, procedure must have two inputs; if there are three data lists, procedure must have three inputs; and so on.

Example:

; Expand rink-counter shorthand to full orders
?to expand :abbrev
>if equal? :abbrev "DD [output [double double]]
>if equal? :abbrev "KD [output [macaroni dinner]]
>output (list :abbrev)
>end
?show map.se "expand [DD KD PB]
[double double macaroni dinner PB]

filter

filter procedure data

operation

filter evaluates procedure once for each member of the data list and outputs a list of those members for which procedure outputs true. Procedure must have one input. The output object will be a word if data is a word; otherwise, the output will be a list.

Procedure must output either true or false for each member of data.

Examples:

?show filter [[x] :x > 2] [1 2 3 4 5]
[3 4 5]
?show filter [[x] 105 < ascii :x] "hello
llo
?

find

find procedure data

operation

find evaluates procedure once for each member of the data list and outputs the first member for which procedure outputs true. Procedure must have one input.

Procedure must output either true or false for each member of data.

Example:

?show find [[x] 0 = remainder :x 2] [1 3 4 5 6]
4
?

reduce

reduce procedure data

operation

reduce evaluates procedure repeatedly to combine the members of data into a single output. Procedure must have two inputs.

If data has only one member, that member is output. If data is empty, an error occurs. Otherwise, the last two members of data are provided as inputs to procedure, and the output of procedure is then combined with the previous member of data by calling procedure again. This process continues until all members of data have been combined.

Examples:

?show reduce [[a b] :a + :b] [1 2 3 4]
10
?
?show reduce [[x y] word :x :y] [a b c d e]
abcde
?
?show reduce [[x y] [(pr "; :x ", :y)] [op :x + :y]] [1 2 3]
; 2 , 3
; 1 , 5
6
?

crossmap

crossmap procedure listlist
(crossmap procedure data1 data2 ...)

operation

crossmap evaluates procedure for every combination of members from the input lists and outputs a list of the results. If more than one data list are given, each of them can be of different lengths. (The data inputs can be words, in which case procedure is evaluated once for each character.)

Each data list provides one input to procedure at each evaluation. Thus, if there are two data lists, procedure must have two inputs; if there are three data lists, procedure must have three inputs; and so on.

As a special case, if only one data list input is given, that listlist is taken as a list of data lists, and each of its members contributes values to an input of procedure.

Examples:

? show crossmap [[x y] :x + :y] [[1 2] [10 20 30]]
[11 21 31 12 22 32]
?
?show (crossmap "word [a b c] [1 2 3 4])
[a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4]
?

===

Special Control Characters

Break

Brk

Pressing Brk immediately stops whatever is running, returning Logo to top level, unless in a pause mode.

F4

F4

Pressing F4 interrupts whatever is running. Typing any character resumes normal execution. This special character is particularly useful in giving yourself time to read when Logo is displaying more than one screenful of information.

F9

F9

Pressing F9 interrupts whatever is running, causing a pause. F9 is equivalent in effect to pause, but different in its use: you press F9 at the keyboard during the running of a procedure, while pause is part of the definition of a procedure.

===

Modifying Procedures Under Program Control

copydef

copydef name newname

command

copydef copies the definition of name, making it the definition of newname as well.

Example:

?to kettle  pr [Tea is ready]  end
?copydef "kettle "thermos
?thermos
Tea is ready

define

define name list

command

define makes list the definition of the procedure name. The first element of list is a list of the inputs to name, with no colon (:) before the names.

If name has no inputs, this must be the empty list. Each subsequent element is a list consisting of one line of the procedure definition. (This list does not contain end, because end is not part of the procedure definition.)

The second input to define has the same form as the output from text. define can redefine an existing procedure.

Example:

?define "notice [[item] [pr se [Found by the rink door:] :item]]
?notice "mitts
Found by the rink door: mitts

defined? (definedp)

defined? word
definedp word

operation

defined? outputs true if word is the name of a user-defined procedure, false otherwise.

Example:

?to maple  pr [Leaf!]  end
?pr defined? "maple
true
?pr defined? "oak
false

primitive? (primitivep)

primitive? name
primitivep name

operation

primitive? outputs true if name is the name of a primitive, false otherwise.

Example:

?pr primitive? "print
true
?pr primitive? "greet
false

text

text name

operation

The text primitive outputs the definition of name as a list of lists, suitable for input to define.

Example:

?to notice :item
>pr se [Found by the rink door:] :item
>end
?show text "notice
[[item] [pr se [Found by the rink door:] :item]]

primitives

primitives

operation

primitives outputs a list of the names of all primitives, in alphabetical order. This list includes the names of all operations and commands described in this reference, as well as some additional primitives that are not described here but are available for use in your programs. The list does not include the names of user-defined procedures.

Example:

?pr member? "print primitives
true
?pr member? "greet primitives
false

help

help name
(help)

command

help outputs a brief description of the primitive name: the type of primitive (command or operation), the inputs it takes, and a quick reminder of its purpose and use.

If name is not the name of a primitive, help searches instead: it lists the primitives whose names contain name, or failing that, the primitives whose descriptions mention it. An error occurs only when nothing matches.

With no inputs, (help) lists every primitive, grouped by the chapters of this manual.

Example:

?help "rand
No help for rand. Related:
  random rerandom
?

===

Logical Operations

and

and predicate1 predicate2
(and predicate1 predicate2 predicate3 ...)

operation

Outputs true if all of its inputs are true. All inputs are evaluated.

Example:

?pr and true true
true
?make "sidewalk "icy
?make "salted true
?pr and equal? :sidewalk "icy :salted
true
?pr and true false
false

not

not predicate

operation

Outputs true if predicate is false.
Outputs false if predicate is true.

Example:

?pr not true
false
?pr not false
true
?make "snowing false
?if not :snowing [pr [Patio season declared]]
Patio season declared

or

or predicate1 predicate2
(or predicate1 predicate2 predicate3 ...)

operation

Outputs true if any of its inputs are true. All inputs are evaluated.

Example:

?pr or false false
false
?pr or false true
true
?make "snack "butter\ tart
?if or equal? :snack "butter\ tart equal? :snack "nanaimo\ bar [pr [Dessert table approved]]
Dessert table approved

===

Bitwise Operations

bitand

bitand num1 num2
(bitand num1 num2 num3 ...)

operation

Outputs the bitwise AND of its inputs, which must be integers.

Example:

?pr bitand 12 10
8
?pr bitand 255 15
15

bitor

bitor num1 num2
(bitor num1 num2 num3 ...)

operation

Outputs the bitwise OR of its inputs, which must be integers.

Example:

?pr bitor 12 10
14
?pr bitor 4 3
7

bitxor

bitxor num1 num2
(bitxor num1 num2 num3 ...)

operation

Outputs the bitwise exclusive OR of its inputs, which must be integers.

Example:

?pr bitxor 12 10
6
?pr bitxor 255 170
85

bitnot

bitnot num

operation

Outputs the bitwise NOT of its input, which must be an integer.

Example:

?pr bitnot 0
-1
?pr bitnot 12
-13

ashift

ashift num1 num2

operation

Outputs num1 arithmetic-shifted to the left by num2 bits. If num2 is negative, the shift is to the right with sign extension. The inputs must be integers.

Example:

?pr ashift 1 4
16
?pr ashift 16 -2
4
?pr ashift -8 -1
-4

lshift

lshift num1 num2

operation

Outputs num1 logical-shifted to the left by num2 bits. If num2 is negative, the shift is to the right with zero fill. The inputs must be integers.

Example:

?pr lshift 1 4
16
?pr lshift 16 -2
4
?pr lshift -8 -1
2147483644

===

The Outside World

key? (keyp)

key? keyp

operation

key? outputs true if there is at least one character waiting to be read-that is, one that has been typed on the keyboard and not yet picked up by readchar or readlist. key? outputs false if there are no such characters.

Example:

?to wait.for.key
>pr [Press any key to continue...]
>until [key?] []
>ignore rc
>end

pollkeys

pollkeys

command

pollkeys refreshes what keydown? and keyhit? report, and discards any characters waiting for readchar.

readchar hands you a stream of characters at the keyboard's typing speed: nothing for a third of a second after a key goes down, then ten repeats a second, queued up in the order they were typed. That is what you want at a prompt and the wrong thing inside a game. A frame loop reading one character a frame takes them out slower than the keyboard puts them in, so the backlog grows and the game acts on a key the player has already let go of; and reading one character at a time means two keys can never be held at once.

pollkeys reads the keyboard's state instead of its history: which keys are down, right now. Call it once at the top of each frame. keydown? and keyhit? afterwards cost nothing, so you can ask about as many keys as your game has controls.

Because a game that polls key state never reads the characters those same keypresses produce, pollkeys throws them away. Call pollkeys once before your loop starts as well, so a keypress left over from a menu is not delivered to the first frame.

Example:

?to play
>pollkeys                    ; ignore whatever started the game
>until [:over] [frame]
>end

keydown? (keydownp)

keydown? code
keydownp code

operation

keydown? outputs true if the key with ASCII code code was held down at the last pollkeys, and false if it was not. It answers for as many frames as the player keeps the key down, which is what a control like steering or thrust wants.

The codes are the ones ascii outputs for ordinary characters — 32 for the space bar, 112 for p — and for the keys that are not characters: 180 left arrow, 183 right arrow, 181 up arrow, 182 down arrow, 13 enter, 8 backspace, 177 escape. Shift, control and alt do not change the code: keydown? 112 is true whether or not shift is down.

Example:

?to steer
>if keydown? 180 [left :turn.rate]
>if keydown? 183 [right :turn.rate]
>if keydown? 181 [thrust]
>end

keyhit? (keyhitp)

keyhit? code
keyhitp code

operation

keyhit? outputs true if the key with ASCII code code was pressed between the last two pollkeys, and false if it was not.

Where keydown? reports that a key is down, keyhit? reports that it went down: once per press, however long the player holds it. Use it for a control that should act once — firing a shot, pausing, choosing a menu item — and keydown? for one that should act continuously.

keyhit? also catches a tap that is over so quickly the key is no longer down by the time pollkeys runs, which keydown? cannot see at all.

Example:

?to poll.input
>pollkeys
>if keyhit? 112 [toggle.pause stop]   ; once per press of P
>if :paused [stop]
>if keydown? 181 [thrust]             ; every frame it is held
>if keyhit? 32 [fire]                 ; one shot per press of space
>end

readchar (rc)

readchar
rc

operation

readchar outputs the first character typed at the keyboard or read from the current file or network connection. If you are reading from the keyboard and no character is waiting to be read, readchar waits until you type something.

readchar does not output a character if you are reading from a file and the end-of-file position is reached. In this case, readchar outputs an empty list. Note that readchar from the keyboard does not echo what you type on the screen.

If reading from a network connection and the read times out before a character is available, readchar outputs an empty list. readchar will also output an empty list if the network connection is closed before a character is available.

If you are reading from the keyboard, you can set the high bit of the character being read by holding down either Alt key a you type the character. Setting the high bit adds 128 to the character.

Example:

?to get.answer
>pr [Press Y for Yes or N for No:]
>make "key rc
>if equal? :key "Y [pr [Oui!]  stop]
>pr [Non!]
>end

readchars (rcs)

readchars integer
rcs integer

operation

The readchars operation outputs the first integer number of characters typed at the keyboard or read from the current file or network connection. If you are reading from the keyboard and no characters are waiting to be read, readchars waits for you to type something.

If you are reading from a file and the end-of-file position reached before integer characters are read, readchars outputs the characters read up to that point. If the end-of-file was reached before readchars was called, readchars outputs an empty list.

If reading from a network connection and the read times out before the requested number of characters are available, readchars outputs the characters read up to that point. If the network connection was closed before readchars was called, readchars outputs an empty list.

Note that readchars from the keyboard does not echo what you type on the screen.

Remember that a carriage return is read as a character.

If you are reading from the keyboard, you can set the high bit of the character being read by holding down either Alt key as you type the character. Setting the high bit adds 128 to character.

Example:

?to read.postal
>pr [Enter first 3 chars of postal code:]
>make "prefix rcs 3
>pr se [Prefix:] :prefix
>end

readlist (rl)

readlist
rl

operation

The readlist operation reads a line of information from the current file or network connection and outputs the information in the form of a list. Normally, the source is the keyboard, where you type in information followed by a carriage return. This information is echoed on the screen. The command setread allows you to read from other files or network connections.

If you are reading from a file where the end-of-file position has already been reached, readlist outputs the empty word.

If you are reading from a network connection and the read times out before a line is available, readlist outputs the characters read up to that point. If the network connection was closed before readlist was called, readlist outputs an empty list.

Example:

?to ask.order
>pr [Enter rink snack order:]
>make "input rl
>pr se [You entered:] :input
>end
?ask.order
Enter rink snack order:
fries gravy
You entered: fries gravy

readword (rw)

readword
rw

operation

readword reads a line of information from the current file or network connection and outputs it as a word. Normally, the source is the keyboard and readword waits for you to type and press Enter. What you type is echoed on the screen. If you press Enter before typing a word, readword outputs an empty word.

If you use readword from a file, readword reads characters until it reaches a carriage return, and outputs those characters as a word. The next character to be read is the one after the carriage return. When the end-of-file position is reached, readword outputs an empty list.

If you are reading from a network connection and the read times out before a line is available, readword outputs the characters read up to that point. If the network connection was closed before readword was called, readword outputs an empty list.

Because readword returns the line verbatim, any vertical bars (see Vertical Bars) are preserved in the resulting word. This differs from readlist and parse, which tokenize the line and so consume the bars while keeping the characters between them.

See readlist, readchar, readchars, and setread.

Example:

?to ask.toque
>pr [Enter toque colour:]
>make "shade rw
>pr se [Toque:] :shade
>end
?ask.toque
Enter toque colour:
red
Toque: red

print object
(print object1 object2 ...)
pr object
(pr object1 object2 ...)

command

The print command prints its inputs followed by a carriage return on the screen, unless the destination has been changed by setwrite. The outermost brackets of lists are not printed. A space is printed between the inputs if there is more than one.

Compare with type and show.

Example:

?pr [Snow route starts at midnight]
Snow route starts at midnight
?pr "sorry
sorry
?(pr "loonie "toonie "hydro)
loonie toonie hydro

show

show object

command

The show command prints object followed by a carriage return on the screen, unless the destination has been changed by setwrite. If object is a list, Logo leaves brackets around it. A space is printed between the inputs if there is more than one.

Compare with type and print.

Example:

?show [loonie toonie hydro]
[loonie toonie hydro]
?show "sorry
sorry

type

type object
(type object1 object2 ...)

command

The type command prints its inputs without a carriage return on the screen, unless the destination has been changed by setwrite. The outermost brackets of lists are not printed. Spaces are not printed between the inputs.

Compare with print and show.

Example:

?type "Rink
?type ": 
?type "closed
Rink: closed

standout

standout object

operation

outputs object in standout mode. In standout mode, text is displayed in reverse video. If the display does not support reverse video, the text is displayed normally. The outermost brackets of lists are not printed.

Example:

?pr standout "Caution
Caution
?pr standout [Slush at door]
Slush at door

toot

toot duration frequency
(toot duration leftfrequency rightfrequency)

command

Generates a tone via audio output. Duration is measured in units of 1/1000th of a second (A whole note is 2000 units; a eighth note is 250 units). A frequency is specified in Hertz (cycles per second) and can range from 131 (C3) to 1976 (B6). 440Hz is the tuning frequency A.

If one frequency is provided the same tone is produced on both left and right channels.

toot does not block. If a second toot is requested, Logo will wait until the previous toot completes.

toot is the simplest way to make a sound. For volume, envelopes, waveforms, noise, and background music, see sound, setenv, setwave, and play.

The actual frequency range is 100Hz to 2000Hz. If the input is outside this range, no tone is produced and but toot behaves as if a rest is requested. By convention, a rest is produced using a frequency of 0Hz.

Example:

; Play A440 for 500ms (like a school gym scoreboard buzzer)
?toot 500 440
; Play two notes: a rising interval
?toot 250 440
?toot 250 523
; Play different tones on left and right channels
?(toot 1000 440 523)

sound

sound voice frequency duration
(sound voice frequency duration volume)

command

Plays a note immediately on voice and returns at once (it does not wait). frequency is in Hertz and duration in milliseconds. volume is 0 to 15; when omitted, the voice's current volume is used (15 until you set one).

There are eight voices, numbered by ear: 0, 1, and 2 are tone voices and 3 is a noise voice on the left channel; 4, 5, and 6 are tone voices and 7 is noise on the right. voice may be a single number or a list of voice numbers, in which case the note plays on each of them (like tell).

The note is shaped by the voice's envelope (setenv) and waveform (setwave). Calling sound on a voice that is playing queued music (see play) flushes that voice's queue - the effect wins.

The frequency range is 20Hz to 10000Hz. A frequency outside this range (including 0) is a rest: the voice is gated off through its release.

Example:

; A 440Hz note for half a second on voice 0
?sound 0 440 500
; A short, loud noise burst - a stereo explosion on both noise voices
?(sound [3 7] 6000 80 15)

setenv

setenv voice [attack decay sustain release]

command

Sets the ADSR envelope of voice. attack, decay, and release are times in milliseconds; sustain is a level from 0 to 15. The envelope shapes every note the voice plays afterwards: the note rises to full volume over attack, falls to the sustain level over decay, holds there while it sounds, then fades over release.

voice may be a single number or a list of voice numbers. The default envelope is [5 0 15 30], which is click-free but otherwise flat, like toot.

Example:

; A percussive pluck: instant attack, quick fall to silence
?setenv 1 [0 60 0 40]
?sound 1 1800 90

env

env voice

operation

outputs the ADSR envelope of voice as the list [attack decay sustain release], as set by setenv. voice must be a single voice number.

Example:

?show env 0
[5 0 15 30]

setwave

setwave voice waveform
(setwave voice "pulse duty)

command

Sets the waveform of voice. For a tone voice (0, 1, 2, 4, 5, 6) waveform is square, pulse, triangle, or sawtooth. For a noise voice (3, 7) it is white or periodic. Using a tone waveform on a noise voice, or a noise waveform on a tone voice, is an error.

With pulse you may give a duty cycle from 1 to 99 (percent); it defaults to 50. voice may be a single number or a list of voice numbers.

Example:

?setwave 0 "triangle
?(setwave 1 "pulse 25)
?setwave 3 "periodic

wave

wave voice

operation

outputs the waveform word of voice, as set by setwave. voice must be a single voice number.

Example:

?show wave 0
square

play

play [notes]
(play voice [notes])

command

Plays a sequence of notes on voice (voice 0 when omitted) in the background: the notes are added to the voice's queue and Logo continues at once. Calling play again on the same voice appends to what is already queued, so a tune can be built up a phrase at a time. voice may be a single number or a list of voice numbers.

Each note is a word:

  • A note is [length] letter [accidental] [octave] [dot]. The letter is a to g. An accidental is # or s for a sharp or b for a flat. The octave is a digit from 1 to 8. A leading length number sets the note length (4 = quarter note, 8 = eighth, and so on); a trailing . dots it. So g is a plain G, 8g an eighth-note G, c#5 a C sharp in octave 5, and 8g#5. a dotted eighth-note G sharp in octave 5.
  • A rest is [length] r [dot], for example 2r for a half rest.
  • Control words change the defaults from that point on: tn sets the tempo in quarter-notes per minute (40 to 300), on the octave (1 to 8), ln the default length (1 to 32), and vn the volume (0 to 15).

If the voice's queue is full, play waits for room (you can interrupt it with the break key), so long tunes stream rather than failing.

Example:

; Frere Jacques, phrase by phrase, as background music
to f1  play [c d e c]  end
to f2  play [e f 2g]  end
?f1 f1 f2 f2
; A drum pattern on the left noise voice
?(play 3 [l8 c c 4c])

playing? (playingp)

playing?
(playing? voice)
playingp
(playingp voice)

operation

outputs true if any voice is currently sounding or still has notes queued, and false if all voices are silent. With a voice argument it asks about that one voice. This pairs well with when to chain music together: when [not playing?] [next.verse].

Example:

?play [c d e c]
?show playing?
true

stopsound

stopsound

command

Silences every voice (through its release) and clears all queued notes. It does not change the envelopes or waveforms set with setenv and setwave, so the timbre you chose survives.

Example:

?play [c d e f g a b c6]
?stopsound

===

Managing your Workspace

nodes

nodes

operation

nodes outputs the number of free nodes. This gives you an idea of how much space you have in your workspace for procedures, variables, properties, and the running of procedures. nodes is most useful if run immediately after recycle.

Words and lists share the interpreter's memory. recycle reclaims storage for words and lists that are no longer reachable, so a program that creates temporary words can recover that space explicitly. Live words still use a 32 KB atom table, so a workspace that keeps too many distinct words can still run out of space.

Example:

?recycle
?pr nodes
14253

atoms

atoms

operation

atoms outputs the number of free bytes in the word table. Words and lists share the interpreter's memory, but they do not share the same shelf: nodes counts the free nodes that lists and procedure bodies are built from, while atoms counts the room left for the characters of distinct words. A program can be rich in one and out of the other, so a program that runs out of space with plenty of nodes free is a program to point atoms at.

Every distinct word costs its characters once, however many places refer to it — and a number stored in a list is a word, so a program storing continuously changing numbers mints a new word for each one. That is the usual reason this figure falls during a loop that looks like it allocates nothing. recycle gives back the room used by words nothing refers to any more.

Example:

?make "l (list 0)
?recycle
?pr atoms
19536
?repeat 100 [make "n random 100000  .setitem 1 :l :n]
?pr atoms
18664
?recycle
?pr atoms
19528

recycle

recycle

command

The recycle command frees up as much unreachable list, word, and blob storage as possible, performing what is called a garbage collection. Logo does not collect garbage on its own: if you run out of space, the current instruction stops with an out of space error, and you must run recycle (typically at a convenient point in your program, such as the top of a main loop) to reclaim unused storage.

Example:

; Free memory before starting the main loop
?recycle
?pr nodes
14253

po

po name
po list

command

The po (for print out) command prints the definition(s) of the named procedure(s).

Example:

?to notice :item
>pr se [Found in lost and found:] :item
>end
?po "notice
to notice :item
pr se [Found in lost and found:] :item
end

poall

poall

command

The poall (for print out all) command prints the definition of every procedure and the value of every variable in the workspace.

Example:

?make "snack "ketchup\ chips
?to hello  pr [Hi]  end
?poall
make "snack "ketchup\ chips
to hello
pr [Hi]
end

pon

pon name
pon list

command

pon (for print out name) prints the name and value of the named variable(s).

Example:

?make "snowbank "tall
?pon "snowbank
make "snowbank "tall

pons

pons

command

pons (for print out names) prints the name and value of every variable in the workspace.

Example:

?make "snack "ketchup\ chips
?make "temp -17
?pons
make "snack "ketchup\ chips
make "temp -17

pops

pops

command

pops (for print out procedures) prints the definition of every procedure in the workspace.

See bury for exceptions.

Example:

?to weather  pr [Chance of flurries]  end
?pops
to weather
pr [Chance of flurries]
end

pot

pot name
pot list

command

The pot (for print out title) command prints the title line of the named procedure(s) in the workspace.

Example:

?to label :item :shelf
>pr (se [Put] :item [on] :shelf)
>end
?pot "label
to label :item :shelf

pots

pots

command

pots (for print out titles) prints the title line of every procedure in the workspace.

See bury for exceptions.

Example:

?to maple  end
?to leaf  end
?pots
to maple
to leaf

erall

erall

command

erall erases all procedures, variables, and properties from the workspace.

See bury for exceptions.

Example:

?make "route "snow
?to hello  pr [Hi]  end
?erall
?pr name? "route
false

erase (er)

erase name
erase list
er name
er list

command

The erase command erases the named procedure(s) from the workspace.

Example:

?to hello  pr [Hello]  end
?defined? "hello
true
?erase "hello
?defined? "hello
false

ern

ern name
ern list

command

The ern (for erase name) command erases the named variable(s) from the workspace.

Example:

?make "toque "red
?pr name? "toque
true
?ern "toque
?pr name? "toque
false

erns

erns

command

erns (for erase names) erases all variables from the workspace.

See bury for exceptions.

Example:

?make "snack "ketchup\ chips
?make "temp -17
?erns
?pr name? "snack
false

erps

erps

command

The erps (for erase procedures) command erases all procedures from the workspace.

See bury for exceptions.

Example:

?to pancake  pr [Needs syrup]  end
?erps
?defined? "pancake
false

bury

bury name
bury list

command

The bury command buries the procedure(s) in its input. Certain commands (erall, erps, poall, pops, pots, and save) act on everything in the workspace except procedures and names that are buried.

Example:

?to startup  pr [Welcome to Pico Logo!]  end
?bury "startup
?pots
; startup is not listed

buryall

buryall

command

The buryall command buries all the procedures and variable names in the workspace.

Once buryall is run, there are no procedure titles or names visible.

Example:

?to greet  pr [Fresh coffee]  end
?make "snack "butter\ tart
?buryall
?pots
; nothing listed

buryname

buryname name
buryname list

command

buryname buries the variable name(s) in its input.

Example:

?make "population 38000000
?buryname "population
?pons
; population is not listed

unbury

unbury name
unbury list

command

The unbury command unburies the named procedure(s).

Example:

?bury "startup
?unbury "startup
?pots
to startup

unburyall

unburyall

command

unburyall unburies all procedures and variable names that are currently buried in the workspace.

Once unburyall is run, the procedures and variable names are visible.

Example:

?buryall
?unburyall
?pots
; all procedures visible again

unburyname

unburyname name
unburyname list

command

unburyname unburies the variable name(s) in its input.

Example:

?buryname "ticket
?unburyname "ticket
?pons
make "ticket "snow\ route

===

File Management

Pico Logo presents a single directory tree with two filesystems mounted in it:

  • / - the root is the device's internal flash storage. It is always present and is where files are saved by default (the default prefix is /). Your startup file lives here as /startup.
  • /sd - the FAT32 SD card, mounted under /sd. It appears in a listing of / only while a card is inserted, and is re-read automatically when a card is removed and another inserted. Asking about /sd with no card present reports There is no SD card.

Paths may be absolute (beginning with /) or relative to the current prefix (see setprefix). rename moves a file between the two filesystems by copying it and deleting the original, while copyfile leaves the original in place. Both work on files only; moving or copying a directory across filesystems is not supported and reports File is the wrong type. Both are binary-safe, so images and other binary files are copied without corruption.

Use free to see how much space remains on a filesystem. The whole internal filesystem can be saved to and reloaded from an SD-card file with backup and .restore.

files

files
(files ext)

operation

Outputs a list of file names in the currect directory. If ext is present, the file names are limited to those with the ext extension. If ext is "*" then all files are output.

Example:

?pr files
[startup rink readme.txt]
?pr (files "txt")
[readme.txt]

directories

directories

operation

Outputs a list of directory names in the current directory.

Example:

?pr directories
[Logo sketches snacks]

createdir

createdir pathname

command

createdir creates the subdirectory indicated by pathname. The last file name in pathname is the subdirectory to be created, and preceding names indicate where it should be placed.

Example:

?createdir "sketches
?pr directories
[sketches]

setprefix (sp)

setprefix pathname
sp pathname

command

Sets a prefix that will be used as the implicit beginning of filenames in open, load, and save commands. The input to setprefix must be a word, unless it is the empty list, to indicate that there should be no prefix. sp is an abbreviation for setprefix.

The pathname can include parent directory references ("..") to navigate up the directory tree. For example, if the current prefix is /sketches/apple/, then setprefix ".." will change the prefix to /sketches/, and setprefix "..\/banana" will change it to /sketches/banana/.

Examples:

?setprefix "/sketches
?pr prefix
/sketches/
?setprefix "apple
?pr prefix
/sketches/apple/
?setprefix "..
?pr prefix
/sketches/
?setprefix "..\/banana
?pr prefix
/sketches/banana/

prefix

prefix

operation

Outputs the current file prefix, or [] if there is no prefix.

Example:

?setprefix "/sketches
?pr prefix
/sketches/
?setprefix []
?pr prefix
[]

editfile

editfile pathname

command

editfile loads the file indicated by pathname into the edit buffer and saves the edited contents under the same filename. The old contents will be lost.

You can use editfile on any file, whether it exists or not. If it does not exist, the editor buffer is erased and Logo creates the file when you save the contents of the edit buffer.

The edit buffer is limited based on Supported Pico Boards. If the file you try to edit contains more than this, Logo displays an error message and does not let you edit the file.

If you exit the editor with Brk, the file remains unchanged.

When exiting the editor, the contents of the buffer are not run.

Example:

?editfile "storm_notes
; Opens the editor with storm_notes contents
; After saving and exiting, the file is updated

erasefile (erf)

erasefile pathname
erf pathname

command

Stands for erase file. Erases any type of file. The input must be the name of a file in the current directory or a full pathname.

Example:

?pr file? "old_data
true
?erasefile "old_data
?pr file? "old_data
false

erasedir

erasedir pathname

command

Stands for erase directory. Erases a directory. The directory must be empty or this command will result in an error.

Example:

?createdir "temp
?erasedir "temp
?pr dir? "temp
false

cat

cat
(cat pathname)

command

Prints the names of the files and directories in the current directory, sorted alphabetically and packed into as many columns as fit across the screen (like a terse ls). Directories have the slash "/" character appended to their name. If pathname is present, it specifies the directory to be listed.

For a detailed one-per-line listing that includes file sizes, use catalog.

cat prints to the screen but not to the current writer.

Example:

?cat
kite       rink       startup
maze       sketches/

catalog

catalog
(catalog pathname)

command

Prints a detailed list of the files and directories in the current directory, one per line, sorted alphabetically (like ls -l). Each line begins with the file's size in bytes, right-aligned; directories have a blank size column and the slash "/" character appended to their name. If pathname is present, it specifies the directory to be listed.

For a compact multi-column listing, use cat.

catalog prints to the screen but not to the current writer.

Example:

?catalog
    418  rink
    212  startup
         sketches/

free

free
(free pathname)

operation

Outputs a two-element list [free_blocks block_size] describing the filesystem that holds the current directory, or - if pathname is given - the filesystem that holds pathname. free_blocks is the number of free allocation blocks; block_size is the size of one block in bytes. A block is the filesystem's own allocation unit (a flash block on the internal / filesystem, a cluster on the /sd card), so block sizes differ between volumes - multiply the two to get free bytes and compare across volumes.

Reports There is no SD card if asked about /sd when no card is present.

Example:

?pr free
1018 4096
?show (free "/sd)
[1962500 8192]
?pr product first free last free
4169728

file? (filep)

file? pathname
filep pathname

operation

Outputs true if the file exists, otherwise false.

Example:

?pr file? "startup
true
?pr file? "missing
false

dir? (dirp)

dir? pathname
dirp pathname

operation

Outputs true if the directory exists, otherwise false.

Example:

?pr dir? "sketches
true
?pr dir? "snacks
false

rename

rename pathname1 pathname2

operation

Renames the file or directory from pathname1 to pathname2. A file or directory can be moved if the paths are different. A file may be moved between the internal storage and the /sd card (it is copied, then the original is deleted); moving a directory across the two filesystems is not supported and reports File is the wrong type.

Example:

?rename "draft "pancake_final
?pr file? "pancake_final
true

copyfile

copyfile pathname1 pathname2

command

Copies the file pathname1 to pathname2, leaving the original in place. If pathname2 already exists it is replaced. The copy is binary-safe, so images and other binary files are copied without corruption, and it may cross between the internal storage and the /sd card (for example copyfile "/sd/turtle.bmp "/turtle.bmp). pathname1 must be a file; copying a directory, or copying onto an existing directory, reports File is the wrong type. Copying a file onto itself has no effect.

Example:

?copyfile "/sd/logo.bmp "/logo.bmp
?pr file? "/logo.bmp
true

backup

backup pathname

command

Writes a complete image of the internal filesystem (/) to pathname, which must be on the SD card (for example backup "/sd/2026-06-30.bak). Only the blocks that actually hold data are written, so the backup file stays small. The image survives re-flashing the firmware, so a backup made before an update can be restored afterwards with .restore.

The backup file must live on the SD card, not on the internal filesystem it is imaging; otherwise Logo reports Backup file must be on the SD card.

Example:

?backup "/sd/2026-06-30.bak
?pr file? "/sd/2026-06-30.bak
true

.restore

.restore pathname

command

Dangerous. Erases the entire internal filesystem (/) and replaces it with the image stored in pathname (which must be on the SD card). Every file currently in internal storage is lost. The leading period marks .restore as a dangerous operation, following Logo convention - there is no undo. All open files are closed before the restore begins.

The image may come from a device with a smaller internal filesystem than this one; the restored filesystem is grown to fill the available space. An image from a larger filesystem cannot be restored onto a smaller one and reports Backup file is not valid for this device. The image is fully checked before any storage is erased, so a corrupt or incompatible backup leaves the existing filesystem untouched.

Example:

?.restore "/sd/2026-06-30.bak

pofile

pofile pathname

command

pofile (for print out file) prints out the contents of the file indicated by pathname. Logo prints the contents to the screen. An error occurs if you try to use pofile on a file that is already open.

pofile prints to the screen but not to the current writer.

Example:

?pofile "winter
to greet
pr [Mitts are in the hall]
end

===

Managing Various Files

load

load pathname

command

The load command loads the contents of the file indicated by pathname into the workspace, as if you typed it directly from top level. An error occurs if the file does not exist.

After Logo loads the contents of a file, it looks for a variable called startup. If one exists, Logo executes its contents.

Demons armed with when while a file loads do not run until the whole file has been read. A demon's action can therefore call a procedure the file defines further down, or load another file. A startup runs after that, with demons live as they are at top level.

Example:

?load "winter
; Loads all procedures and variables from winter

save

save pathname

command

The save command creates a file and saves in it all unburied procedures and variables and all properties in the workspace. An error occurs if the file you name already exists. In this case, you should first either erase the existing file using erasefile or rename it using rename.

Example:

?to greet  pr [Fresh coffee]  end
?save "winter
; Saves all procedures and variables to winter

savel

savel name pathname
savel namelist pathname

command

The savel command saves the procedures named in name or namelist, and all the unburied variables and properties in the workspace to pathname. An error occurs if any of the procedures named in name or namelist do not exist in the workspace, or if the file you name already exists. In this case, you should first either erase the existing file using erasefile or rename it using rename. This command is useful for saving a portion of your workspace onto a SD Card. Compare it with save.

Example:

?to greet  pr [Hello]  end
?to farewell  pr [Goodbye]  end
?savel [greet farewell] "greetings
; Saves only greet and farewell procedures

loadpic

loadpic pathname

command

The loadpic command loads the picture named by pathname onto the graphics screen. Logo will only load 8-bit indexed color BMP onto the graphics screen. The palette will be changed to match that in the BMP file.

Example:

; Load a grey jay image onto the graphics screen
?loadpic "greyjay.bmp

savepic

savepic pathname

command

savepic saves the graphics screen into the file indicated by pathname. You can retrieve the screen later using loadpic. The image is saved as a 8-bit indexed color BMP (.bmp) file.

Example:

; Draw something then save the screen
?repeat 4 [fd 50 rt 90]
?savepic "rink.bmp

dribble

dribble file

command

dribble starts the process of sending a copy of the characters displayed on the text screen to file. dribble records interactions between the PicoCalc and the person at the keyboard. dribble automatically opens file. nodribble stops the process of dribbling. You cannot use setread or setwrite with a dribble file while still dribbling. However, once a dribble file on disk has been closed with nodribble, you can treat it like any other file. You can then open it, read from it, or write to it. Note that only one dribble file can be open at one time.

Example:

?dribble "session.txt
?pr [Hello from the rink!]
Hello from the rink!
?nodribble
; session.txt now contains the interaction

nodribble

nodribble

command

nodribble turns off the dribble feature so a copy of the characters from the screen will no longer be sent to the file or device named previously by the dribble command.

Example:

?dribble "log.txt
?pr [Logging session...]
?nodribble

===

Input and Output to Files, Network Connections and Devices

These commands and operations allow you to open files and network connections, read from and write to them, and close them when you are finished.

A network connection is specified as a word in this format: host:port. For example, to open a connection to the host myserver.com on port 8080, you would use the word "myserver.com:8080. The host can be a domain name or an IP address in dotted decimal format (for example, "192.168.1.100:8080). The port must be a number between 1 and 65535. If this pattern is not matched, Logo assumes you are referring to a file.

The screen and keyboard are devices and are special. You cannot open or close them. To select the keyboard as the current reader, use the setread command with the empty list as input. To select the screen as the current writer, use the setwrite command with the empty list as input.

allopen

allopen

operation

allopen outputs a list of all files and network connections currently open. The open command opens a file or a network connection.

Example:

?open "notes
?open "log.txt
?show allopen
[notes log.txt]

close

close target

command

The close command closes the named file or network connection that is currently open. See open to open a file or network connection. An error occurs if you try to use close with a file or network connection that is not open. An error also occurs if you try to use close with a file or network connection that is opened by the dribble command.

Example:

?open "log.txt
?setwrite "log.txt
?pr [Session started after snow clearing]
?setwrite []
?close "log.txt

closeall

closeall

command

The closeall command closes all files and network connections that are currently open. Dribble files are not closed with closeall. Use the open and close commands to open and close one file at a time. If you try to use closeall when no files or network connections are open, it is ignored.

See nodribble for closing dribble files.

Example:

?open "data.txt
?open "log.txt
?closeall
?show allopen
[]

filelen

filelen file

operation

filelen outputs the length in bytes of the contents of the file indicated by file. The file must be open to use this primitive. An error occurs if the file is not open.

This procedure returns an error if the file is a network connection.

Example:

?open "notes
?pr filelen "notes
1024
?close "notes

open

open target

command

The open command opens target so it can send or receive characters. You must open a file or network connection before you can access it. You can open a maximum of eight files or network connections at once.

If the file named by target does not exist, then open creates the file.

If target is a host:port, open establishes a TCP connection to the specified host:port. An error occurs if the connection cannot be established.

Once a file or network connection is open, you use setread and setwrite to set the read and write for the file or network connection. Then you can use the standard reading and writing commands access the file or to communicate over the network.

When you finish using Logo, you must close all files and network connections that are open, see the close, closeall and goodbye commands.

Example:

?open "log.txt
?setwrite "log.txt
?pr [Logging from the basement workbench]
?setwrite []
?close "log.txt

reader

reader

operation

reader outputs the current file or network connection that is open for reading. You can change the current read file with the setread primitive. reader returns the name of the file, the network connection or the empty list if the current reader is the keyboard.

Example:

?pr reader
[]
?open "recipes.txt
?setread "recipes.txt
?pr reader
recipes.txt

readpos

readpos

operation

readpos (for read position) outputs the position in the current reader. An error occurs if the current reader is a network connection or the keyboard. To set the position in the read file, see the setreadpos command.

Example:

?open "notes
?setread "notes
?pr readpos
0
?ignore readword
?pr readpos
12

setread

setread target

command

setread sets the current reader to target. After you give this command, readlist, readword, readchar, and readchars read information from this file or network connection.

Before you use setread, you must open the file or network connection with the open command. An error occurs if the file or network connection is not open.

To set the current reader back to the keyboard, give setread the empty list as input.

Example:

?open "recipes.txt
?setread "recipes.txt
?pr readword
buttertarts
?setread []
; back to reading from keyboard

setreadpos

setreadpos integer

command

setreadpos sets the read position in the current reader. The integer should be a number between 0 and the current length of the file. An error occurs if it is not in this range. An error also occurs if the current reader is a network connection or the keyboard.

See readpos for more information about the setreadpos command.

Example:

?open "notes
?setread "notes
?setreadpos 0
?pr readpos
0

setwrite

setwrite target

command

setwrite sets the current writer to the file, network connection or the screen you name. The primitives print, type, and show all print to the current writer. You cannot use setwrite unless the file or network connection has previously been opened.

Before you use setwrite, you must open the file or network connection with the open command. An error occurs if the file or network connection is not open.

To restore the screen as the current writer, use the setwrite command with the empty list as input.

The commands po, poall, pon, pons, pops, pot, pots, and pofile all print to the screen but not to the current writer.

Example:

?open "log.txt
?setwrite "log.txt
?pr [Logged from the rink]
?setwrite []
?close "log.txt

setwritepos

setwritepos integer

command

setwritepos sets the write position in the current file. This command is useful when modifying information in a file. You must set the write position to a number that is between 0 and the end-of-file position. If you try to set it somewhere out of this range, an error occurs. An error also occurs if you try to set the write position when the current writer is the screen or a network connection.

To check the current position, use the writepos command.

Example:

?open "log.txt
?setwrite "log.txt
?pr [line one]
?pr writepos
9
?setwritepos 0
?pr writepos
0

writepos

writepos

operation

writepos (for write position) outputs where in the current write file the the next character will be written. An error occurs if the current writer is the screen or a network connection.

Example:

?open "log.txt
?setwrite "log.txt
?pr [Hydro]
?pr writepos
6

writer

writer

operation

writer outputs the current file, network connection, or the empty list if the current writer is the screen. Compare this with the allopen operation.

Example:

?pr writer
[]
?open "log.txt
?setwrite "log.txt
?pr writer
log.txt
?setwrite []

.timeout

.timeout

operation

timeout outputs the current timeout value in milliseconds for network operations. A timeout value of 0 indicates that there is no timeout.

Example:

?pr .timeout
0
?.settimeout 5000
?pr .timeout
5000

.settimeout

.settimeout integer

command

The settimeout command sets the timeout value for network operations to integer milliseconds. A timeout value of 0 indicates that there is no timeout. If a network operation does not complete within the specified time, it fails with an error.

Example:

; Set 5 second timeout for network operations
?.settimeout 5000
?pr .timeout
5000

===

Time Management

ticks

ticks

operation

ticks outputs the number of milliseconds since the device started, as a plain number. It's a monotonic clock - it never jumps backward and isn't affected by settime/setdate - so it's the right tool for timing an interval: read it before and after, and subtract. It wraps around after about 49.7 days of continuous uptime.

Logo numbers are single-precision floating point, which represents integers exactly only up to 16,777,216. After about 4.66 hours of uptime, ticks can no longer distinguish every individual millisecond - fine for timing anything from a game frame to a long wait, but not for measuring uptime itself to the millisecond after that long.

Example:

?make "start ticks
?repeat 100000 [pr "tick]
...
?pr (ticks - :start)
842
; that repeat took 842 milliseconds

date

date

operation

date outputs the current date as a list in the form [year month day], where year is the full year (e.g., 2026), month is a number from 1 to 12, and day is a number from 1 to 31.

Example:

?show date
[2026 7 1]
; July 1, after the fireworks are swept up
?make "d date
?pr se [Year:] item 1 :d
Year: 2026

time

time

operation

time outputs the current time as a list in the form [hour minute second], where hour is a number from 0 to 23, minute is a number from 0 to 59, and second is a number from 0 to 59.

Example:

?show time
[14 30 0]
; 2:30 PM Eastern Time
?make "t time
?pr se [Hour:] item 1 :t
Hour: 14

setdate

setdate [year month day]

command

The setdate command sets the current date to the specified year, month, and day. An error occurs if the date is not valid.

Example:

; Set date to a long-weekend morning
?setdate [2026 7 1]
?show date
[2026 7 1]

settime

settime [hour minute second]

command

The settime command sets the current time to the specified hour, minute, and second. An error occurs if the time is not valid.

Example:

; Set time to noon
?settime [12 0 0]
?show time
[12 0 0]

===

WiFi Management

These procedures allow you to manage the WiFi connection of the device.

wifi? (wifip)

wifi?

operation

wifi? outputs true if the WiFi is connected, otherwise it outputs false.

Example:

?pr wifi?
false
?wifi.connect "TimHortonsWiFi "double-double
?pr wifi?
true

tls? (tlsp)

tls?

operation

tls? outputs true if this board can open https:// connections, otherwise it outputs false. TLS needs PSRAM to hold the handshake buffers, so a board with WiFi but no PSRAM (such as the Pico 2 W) can still use http.get on http:// URLs while tls? outputs false. Unlike wifi?, this reports a fixed hardware capability rather than the live connection state.

Example:

?pr tls?
true
?if tls? [pr http.get "https://example.com/] [pr [no https on this board]]

wifi.mac

wifi.mac

operation

wifi.mac outputs the MAC address of the device as a word of six hexadecimal numbers separated by colons, each between 0 and FF. The MAC address is a unique identifier for the device on a network.

Example

?wifi.mac
00:00:5E:12:34:56

wifi.connect

wifi.connect ssid password

command

The wifi.connect command connects to the WiFi network with the given ssid and password. If the connection is successful, wifi? will output true. If the connection fails, an error message is displayed.

wifi.connect waits for the network to answer, which can take several seconds — and up to thirty if the network is out of range. Use wifi.start instead when you would rather carry on working while the connection is made.

Example:

?wifi.connect "TimHortonsWiFi "double-double
?pr wifi?
true
?pr wifi.ssid
TimHortonsWiFi

wifi.start

wifi.start ssid password

command

The wifi.start command begins connecting to the WiFi network with the given ssid and password, but does not wait for the result. Unlike wifi.connect, it finishes at once, so the rest of your program — or your startup file — keeps running while the network connects in the background.

Use wifi? or wifi.status to find out how the connection is getting on. A when demon is the tidiest way to wait for it, because it lets you do something the moment the network is ready:

?wifi.start "TimHortonsWiFi "double-double
?when [wifi?] [network.ntp -4  pr [clock set]]

The demon fires once, as soon as the device has an address on the network. Until then wifi? outputs false, and the rest of your program runs normally.

wifi.start keeps trying until it succeeds, so it copes with a network that needs several attempts or is not yet switched on. It stops only for a refused password, or when you call wifi.disconnect. wifi.status says how it is getting on; an error is displayed only when the attempt cannot be started at all, such as on a board with no radio.

wifi.status

wifi.status

operation

wifi.status outputs a word describing the state of the WiFi connection:

OutputMeaning
offNot connected, and nothing is being attempted
connectingLooking for the network and joining it
noaddressJoined the network; waiting for it to assign an address
connectedConnected, with an address on the network
notfoundThe network was not found
badpasswordThe network refused the password
failedJoining the network failed for some other reason

The first four are the stages of a connection in progress; the last three say where it went wrong.

Joining a network is often unreliable: an attempt may fail outright, be missed by a scan, or join and then never get around to assigning an address. On some networks it simply takes several tries. So wifi.start keeps trying — whenever a connection stops making progress for a few seconds, it quietly begins another attempt, and it goes on doing so until it connects. This means a device left switched on will join the network whenever it becomes reachable, even if that is some time later.

Two things stop it: wifi.disconnect, and a refused password, since that will not come right however many times it is tried.

So failed, notfound and noaddress are ordinary sights along the way and do not mean Pico Logo has given up — each one is simply the attempt that just ended. Only badpassword is final. If you want to report a problem without repeating yourself every few seconds, count the attempts rather than printing on each one:

make "tries 0
when [equal? wifi.status "failed] ~
     [make "tries :tries + 1
      if :tries = 5 [pr [Still cannot join the network]]]

Example:

?wifi.start "TimHortonsWiFi "double-double
?pr wifi.status
connecting
?pr wifi.status
noaddress
?pr wifi.status
connected

To watch the whole sequence — useful when a connection is not coming up, and the fastest way to see which stage it stalls at:

make "last "off
wifi.start "TimHortonsWiFi "double-double
when [not equal? wifi.status :last] [make "last wifi.status  pr :last]

wifi.status outputs connected in exactly the cases where wifi? outputs true. It is most useful after wifi.start, where it tells you whether an attempt is still going or has given up — something wifi? alone cannot say.

Example:

?wifi.start "TimHortonsWiFi "double-double
?pr wifi.status
connecting
?pr wifi.status
connected

wifi.ip

wifi.ip

operation

wifi.ip outputs the current IP address assigned to the device by the WiFi network. If the device is not connected to a WiFi network, wifi.ip outputs the empty list.

Example:

?wifi.connect "TimHortonsWiFi "double-double
?pr wifi.ip
192.168.1.42

wifi.ssid

wifi.ssid

operation

wifi.ssid outputs the SSID of the WiFi network to which the device is currently connected. If the device is not connected to a WiFi network, wifi.ssid outputs the empty list.

Example:

?pr wifi.ssid
TimHortonsWiFi

wifi.disconnect

wifi.disconnect

command

The wifi.disconnect command disconnects the device from the current WiFi network. After executing this command, wifi? will output false.

Example:

?pr wifi?
true
?wifi.disconnect
?pr wifi?
false

wifi.scan

wifi.scan

operation

wifi.scan outputs a list of available WiFi networks. Each network is represented as a sublist containing the SSID and signal strength.

Example:

?show wifi.scan
[[TimHortonsWiFi -65] [HarveysWiFi -72] [HomeNetwork -48]]

wifi.sethostname

wifi.sethostname name

command

The wifi.sethostname command sets the device's network name to name. Once WiFi is connected, other machines on the same network can reach the device by this name with .local added — for example http://picologo.local — instead of its numeric IP address. The same name is given to the router as the device's DHCP hostname.

name must be a word of letters, digits, and hyphens (a hyphen may not be the first or last character), up to 32 characters long, and must not contain a dot: the .local part is added automatically. The default name is picologo, and it returns to picologo each time the device restarts, so put a wifi.sethostname line in your startup file to keep a custom name. If WiFi is already connected, the new name takes effect immediately.

Example:

?wifi.sethostname "picocalc
?wifi.connect "TimHortonsWiFi "double-double
?pr wifi.hostname
picocalc

Now http://picocalc.local reaches the device from a phone or laptop on the same network.

wifi.hostname

wifi.hostname

operation

wifi.hostname outputs the device's current network name (the name set by wifi.sethostname, without the .local suffix). The default is picologo.

Example:

?pr wifi.hostname
picologo
?wifi.sethostname "myturtle
?pr wifi.hostname
myturtle

===

Network Operations

network.ping

network.ping ipaddress

operation

The network.ping operation sends a ping request to the specified ipaddress. It outputs the number of milliseconds it took for the response if a response is received, otherwise it outputs -1. The ipaddress should be in standard dotted-decimal notation (e.g., "192.168.1.1").

Example:

?pr network.ping "8.8.8.8
14
?pr network.ping "192.168.1.1
2

network.resolve

network.resolve hostname

operation

The network.resolve operation takes a hostname (e.g., "www.example.com") and outputs its corresponding IP address in dotted-decimal notation. If the hostname cannot be resolved, it outputs the empty list.

Example:

?pr network.resolve "canada.ca
192.197.168.105

network.ntp

network.ntp
(network.ntp timezone)
(network.ntp timezone serveraddress)

operation

The network.ntp operation synchronizes the device's internal clock with a Network Time Protocol (NTP) server. It outputs true if the synchronization is successful, otherwise it outputs false. Ensure that the device is connected to a WiFi network before using this command.

If the synchronization succeeds, the device's date and time are updated to match the NTP server. If timezone is provided, the time is adjusted accordingly; otherwise, it defaults to UTC. timezone is specified in hours relative to UTC (e.g., -5 for EST, 1 for CET), and can include fractional hours (e.g., 5.5 for IST).

The default NTP server is "pool.ntp.org". You can specify a different server by providing its serveraddress as an argument.

Example:

; Sync time with EST timezone (UTC-5)
?pr (network.ntp -5)
true
?show time
[14 30 0]

===

HTTP Operations

These operations fetch and send data over the web. They require that the device is connected to a WiFi network (see wifi.connect); an error occurs if WiFi is not available or not connected.

A url is a word beginning with http:// or https://, for example "http://example.com/index.html, "https://example.com/index.html, or "http://example.com:8080/api. If no port is given, port 80 is used for http:// and port 443 for https://.

For an https:// url the connection is encrypted with TLS, and the server's certificate is verified: its chain must lead to one of the certificate authorities built into Pico Logo, and the certificate must match the host name in the url. If verification fails, the request fails to complete (an error you can trap with catch), exactly like a refused connection. Only a trimmed set of common certificate authorities is built in, so a host using an uncommon authority may not be trusted even though it is otherwise valid. Certificate expiry is not checked, because the device has no reliable clock at the time of the request.

Request headers are supplied as extra inputs in name/value pairs, using the parenthesised form of the operation, for example (http.get "http://example.com/ "Accept "text/plain). Each name and value is a word. Recall that a quoted word may contain - and / without a backslash (so "Content-Type and "text/plain are each a single word); a value that contains spaces cannot be written as a quoted word.

Each operation performs one complete request: it opens a connection, sends the request, reads the whole response, and closes the connection. The connection is not left open and does not appear in allopen. The read timeout is governed by .settimeout; if the server does not respond in time, the operation produces an error.

A request can fail to complete (the host cannot be resolved, the connection is refused, the request times out, or the response is larger than the device can hold). In these cases the operation produces an error, which you can trap with catch. A request that completes produces a result even when the server reports a problem: a "404 Not Found" response is not an error; the operation outputs the server's response body, and http.status outputs 404.

The response body is held as a single word. There is a fixed maximum size; a response whose body exceeds it produces an error rather than a truncated result.

After any successful request, http.status and http.header describe the most recent request. Making another request replaces this information.

http.get

http.get url
(http.get url name1 value1 name2 value2 ...)

operation

The http.get operation sends an HTTP GET request to url and outputs the response body as a word.

In the second form, the extra inputs are request headers given as name/value word pairs, for example (http.get "http://example.com/ "Accept "text/plain "User-Agent "PicoLogo). An odd number of header inputs (a name with no value) produces an error.

If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.

Example:

?pr http.get "http://example.com/menu.txt
Today's special is poutine.
?pr http.status
200

http.post

http.post url data
(http.post url data name1 value1 name2 value2 ...)

operation

The http.post operation sends an HTTP POST request to url with data as the request body, and outputs the response body as a word. data may be a word or a list; a list is sent as its members separated by spaces, with no outer brackets.

In the second form, the extra inputs are request headers given as name/value word pairs, in the same way as http.get.

If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.

Example:

?pr (http.post "http://example.com/orders [pierogi fries] "Content-Type "text/plain)
Order received.
?pr http.status
201

http.put

http.put url data
(http.put url data name1 value1 name2 value2 ...)

operation

The http.put operation sends an HTTP PUT request to url with data as the request body, and outputs the response body as a word. It behaves exactly like http.post apart from the request method: data may be a word or a list, and the parenthesised form takes request headers as name/value word pairs.

PUT is normally used to create or replace the resource at url with the supplied data.

If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.

Example:

?pr (http.put "http://example.com/orders/17 [pierogi fries] "Content-Type "text/plain)
Order updated.
?pr http.status
200

http.patch

http.patch url data
(http.patch url data name1 value1 name2 value2 ...)

operation

The http.patch operation sends an HTTP PATCH request to url with data as the request body, and outputs the response body as a word. It behaves exactly like http.post apart from the request method: data may be a word or a list, and the parenthesised form takes request headers as name/value word pairs.

PATCH is normally used to apply a partial update to the resource at url.

If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.

Example:

?pr (http.patch "http://example.com/orders/17 [fries] "Content-Type "text/plain)
Order updated.
?pr http.status
200

http.delete

http.delete url
(http.delete url name1 value1 name2 value2 ...)

operation

The http.delete operation sends an HTTP DELETE request to url and outputs the response body as a word. It sends no request body; in the parenthesised form the extra inputs are request headers given as name/value word pairs, in the same way as http.get.

DELETE is normally used to remove the resource at url.

If the request cannot be completed, an error occurs. If the request completes, use http.status to find out whether the server reported success.

Example:

?pr http.delete "http://example.com/orders/17
Order deleted.
?pr http.status
204

http.status

http.status

operation

The http.status operation outputs the numeric HTTP status code of the most recently completed request made by http.get, http.post, http.put, http.patch, or http.delete, for example 200 for success or 404 for "Not Found". If no request has been made, it outputs the empty list.

Example:

?pr http.get "http://example.com/missing.txt
Not Found
?pr http.status
404

http.header

http.header name

operation

The http.header operation outputs the value of the response header named name from the most recently completed request, as a word. The name is matched without regard to upper and lower case. If the most recent response did not include that header, or if no request has been made, it outputs the empty list.

Example:

?pr http.get "http://example.com/menu.txt
Today's special is poutine.
?pr http.header "Content-Type
text/plain
?pr http.header "X-Not-Present
[]

===

HTTP Server

These primitives let a Logo program answer HTTP requests — controlling the turtle from a phone browser, or transferring files without a cable — on the WiFi boards (the Pico 2 W and the Pico Plus 2 W).

The server handles one request at a time. http.listen starts it; each request that arrives makes http.request? output true, and a handler answers it with http.respond (see the request accessors and http.respond that follow). The usual shape is a when demon, which keeps serving while the program runs and while you type at the prompt:

wifi.connect "TimHortonsWiFi "double-double
http.listen 80
when [http.request?] [
  if equal? http.path "/forward [fd 20]
  if equal? http.path "/right   [rt 90]
  http.respond 200 sentence [heading is] heading
]
pr sentence [serving at] wifi.ip

With mDNS naming (see wifi.sethostname), the browser can reach the device at http://picologo.local instead of its IP address.

The server closes automatically when a running program stops with an error — so a serving program that errors stops serving; rerun it to restart. clearscreen does not close it: a program that redraws the screen keeps serving. Requests that are malformed, that stall halfway, whose body is too large, or that no handler answers within ten seconds are given an automatic error response and closed, so a connection is never left hanging.

http.listen

http.listen port

command

The http.listen command starts the HTTP server listening on port (a whole number from 1 to 65535). A browser reaches a server on port 80 without a port suffix in the address. It is an error to http.listen when the WiFi is not connected. Calling http.listen again on the same port does nothing, so a program that starts with it can be rerun freely; calling it on a different port moves the server to that port.

Example:

?wifi.connect "TimHortonsWiFi "double-double
?http.listen 80
?pr sentence [serving at] wifi.ip
serving at 192.168.1.42

http.unlisten

http.unlisten

command

The http.unlisten command stops the HTTP server and drops any connection in progress. It does nothing if the server is not listening. The server is also stopped automatically when a program unwinds to the prompt with an error.

Example:

?http.unlisten

http.request? (http.requestp)

http.request?

operation

http.request? outputs true when a complete request has arrived and is waiting for a response, otherwise it outputs false. It is the condition of the serving when demon, and can equally drive an ordinary polling loop:

http.listen 80
forever [if http.request? [http.respond 200 "hello]]

Example:

?pr http.request?
false

http.method

http.method

operation

http.method outputs the HTTP method of the pending request — GET, POST, PUT, and so on — as a word. It is an error to use it when no request is pending (see http.request?).

Example:

when [http.request?] [
  if equal? http.method "GET [http.respond 200 "hello]
]

http.path

http.path

operation

http.path outputs the path of the pending request as a word, with any percent-escapes (such as %20 for a space) decoded and the query string removed. For a request to /turtle/forward?steps=20 it outputs /turtle/forward. It is an error to use it when no request is pending.

Example:

when [http.request?] [
  if equal? http.path "/forward [fd 20]
  http.respond 200 "ok
]

http.query

http.query

operation

http.query outputs the query string of the pending request — the part after the ? — as a word, or the empty word if the request had no query string. For a request to /draw?colour=red&size=3 it outputs colour=red&size=3. The parts can then be split apart in Logo. It is an error to use it when no request is pending.

Example:

?pr http.query
steps=20&turn=left

http.body

http.body

operation

http.body outputs the body of the pending request as a word, or the empty word for a request with no body (such as a GET). It is an error to use it when no request is pending. It is also an error if the body was too large to hold in memory (a large upload); use http.savebody to stream such a body straight to a file instead.

Example:

when [http.request?] [
  if equal? http.method "POST [make "note http.body]
  http.respond 200 "saved
]

http.reqheader

http.reqheader name

operation

http.reqheader outputs the value of the request header named name as a word, matching name without regard to upper and lower case. If the pending request has no such header it outputs the empty list. It is an error to use it when no request is pending. This is how a handler reads a shared-secret header to protect against unwanted callers.

Example:

when [http.request?] [
  ifelse equal? http.reqheader "X-Key "swordfish ~
    [http.respond 200 "welcome] ~
    [http.respond 403 "no]
]

http.remote

http.remote

operation

http.remote outputs the IP address of the client that made the pending request, as a word, useful for logging or greeting. It is an error to use it when no request is pending.

Example:

?pr http.remote
192.168.1.87

http.respond

http.respond status body
(http.respond status body name1 value1 ...)

command

The http.respond command answers the pending request and closes the connection. status is the HTTP status code (such as 200 for success or 404 for not found), and body is a word or list sent as the response body, formatted as print would show it. The response is sent with Content-Type: text/plain; charset=utf-8 unless you override it.

In the parenthesised form, the extra inputs are name / value word pairs added as response headers — the same convention as (http.get url name value ...). Supplying a Content-Type header replaces the default, so an HTML page displays correctly in a browser. It is an error to use http.respond when no request is pending.

Example:

when [http.request?] [
  http.respond 200 sentence [heading is] heading
]

Serving HTML built with http.element (see below), overriding the content type:

when [http.request?] [
  (http.respond 200 http.element "h1 [Hello from Pico Logo] "Content-Type "text/html)
]

http.respondfile

http.respondfile status path
(http.respondfile status path name1 value1 ...)

command

The http.respondfile command answers the pending request with the contents of the file named path as the response body, then closes the connection. The file is sent in small pieces, so it can be any size and may contain binary data (such as a picture) — nothing is limited by the size of memory. The response is sent with Content-Type: application/octet-stream unless you override it with a Content-Type header in the parenthesised form.

If the file does not exist, http.respondfile reports an ordinary error and leaves the request pending, so a handler can catch it and answer with a 404 instead. A path containing .. is rejected. It is an error to use http.respondfile when no request is pending.

Example — a tiny file server that also serves a not-found page:

when [http.request?] [
  ifelse file? http.path ~
    [http.respondfile 200 http.path] ~
    [http.respond 404 [not found]]
]

http.savebody

http.savebody path

command

The http.savebody command writes the body of the pending request to the file named path, streaming it straight to storage in small pieces. This is how you receive an uploaded file (for example from curl -T): the upload can be any size and may be binary, even larger than would fit in memory. The request stays pending afterwards, so the handler still finishes by answering with http.respond. A path containing .. is rejected, and it is an error to use http.savebody when no request is pending.

Example — accept uploads with PUT and serve files with GET:

when [http.request?] [
  if equal? http.method "PUT [http.savebody http.path  http.respond 201 "saved]
  if equal? http.method "GET [http.respondfile 200 http.path]
]

Upload and download from a computer on the same network:

curl -T invaders http://picologo.local/invaders
curl -o copy.txt http://picologo.local/notes.txt

http.element

http.element tag content
(http.element tag content name1 value1 ...)

operation

http.element builds an HTML element as a word: <tag>content</tag>. content is a word or a list; a list is formatted as print would show it (its spaces come through and its outer brackets are dropped), and because the result is a word, elements nest by passing one http.element as the content of another.

In the parenthesised form the extra inputs are name / value word pairs added as attributes, so (http.element "a "forward "href "/forward) builds <a href=/forward>forward</a>. This spares you from spelling out the angle brackets with char 60 and char 62, which the Logo lexer would otherwise require. Attribute values are single words; because the lexer treats = and : as delimiters, escape them with a backslash inside a value (for example "margin\=0).

Example:

?pr http.element "h1 [Pico Logo Turtle]
<h1>Pico Logo Turtle</h1>
?pr (http.element "p (http.element "a "left "href "/left))
<p><a href=/left>left</a></p>

The inner element needs its own parentheses so its attribute pair belongs to it rather than to the outer element.

===

Property Lists

erprops

erprops

command

erprops (for erase properties) erases all properties from the workspace. To check which property lists are currently in the workspace, use pps. Use remprop to remove properties one at a time from the workspace.

Example:

?pprop "loonie "value "one
?erprops
?pr gprop "loonie "value
[]

gprop

gprop name property

operation

gprop (for get property) outputs the value of property of name. If there is no such property, gprop outputs the empty list.

Example:

?pprop "toque "season "winter
?pprop "toque "drawer "hall
?pr gprop "toque "season
winter
?pr gprop "toque "pom
[]

plist

plist name

operation

plist outputs the property list associated with name. This is a list of property names paired with their values, in the form [prop1 vall prop2 val2 ...].

Example:

?pprop "ferry "status "delayed
?pprop "ferry "dock "three
?show plist "ferry
[status delayed dock three]

pprop

pprop name property object

command

The pprop (for put property) command gives name property with value object. Note that erall erases procedures, variables, and properties. Use remprop to erase properties one at a time or erprops to erase them all at once.

Example:

?pprop "buttertart "filling "raisins
?pprop "buttertart "debate "lively
?pr gprop "buttertart "filling
raisins
?show plist "buttertart
[filling raisins debate lively]

pps

pps

command

The pps (for print properties) command prints the property lists of everything in the workspace.

Example:

?pprop "loonie "value "one
?pprop "toonie "value "two
?pps
plist "loonie [value one]
plist "toonie [value two]

remprop

remprop name property

command

The remprop (for remove property) command removes property from the property list of name.

See pprop and gprop.

Example:

?pprop "snowroute "starts "midnight
?pprop "snowroute "zone "blue
?remprop "snowroute "zone
?show plist "snowroute
[starts midnight]

===

JSON

A JSON document is held as text - typically the word returned by http.get. json.get reads values straight out of that text, so even a large response (which is kept in PSRAM) can be queried without copying the whole document into the workspace.

json.get

json.get document path

operation

json.get outputs the value found by following path into document. Document is a word containing JSON text. Path is a list of steps: a word selects a member of an object by key (case-sensitive, as in JSON), and a number selects an element of an array by position (1-based, like item).

A string value is output as a word with its JSON escapes resolved; a number is output as a numeric word (usable directly in arithmetic); true and false are output as the words true and false; and null is output as the empty list. A nested object or array is output as its raw JSON text, which can be passed back to json.get to read further. If any step does not match, json.get outputs the empty list. An empty path outputs the whole document.

Example:

?make "person json.get http.get "https\://example.com/me []
?show json.get :person [name]
Blair
?show json.get :person [tags 2]
c
?show json.get :person [address city]
Ottawa
?show json.get :person [missing]
[]

json.count

json.count value

operation

json.count outputs the number of elements in a JSON array, or the number of members in a JSON object, where value is a word containing that JSON text. A scalar value outputs 0, and the empty list - the result of json.get for a missing path or JSON null - also outputs 0, so json.count json.get ... can be used directly as a loop bound.

Example:

?make "person json.get http.get "https\://example.com/me []
?show json.count json.get :person [tags]
3
?for [i 1 [json.count json.get :person [tags]]] [pr json.get :person (list "tags :i)]
logo
c
rp2350

json.object

(json.object key1 value1 key2 value2 ...)

operation

json.object builds a JSON object from the given key/value pairs. Each key must be a word. A value may be a word (output as a JSON string), a number, the words true or false, the empty list (output as null), a list (output as a JSON array), or another json.object or json.array. The result is passed to json.make to produce JSON text. Give the inputs as quoted words rather than inside a list, so values containing /, - or spaces are kept intact.

See json.array and json.make.

Example:

?show json.make (json.object "name "Blair "age 42)
{"name":"Blair","age":42}

json.array

(json.array value1 value2 ...)

operation

json.array builds a JSON array from the given values, each encoded in the same way as a json.object value. The result is passed to json.make to produce JSON text. An empty array is (json.array).

See json.object and json.make.

Example:

?show json.make (json.array "logo "c "rp2350)
["logo","c","rp2350"]

json.make

json.make value

operation

json.make outputs the JSON text for value. Value is usually built with json.object and json.array, but may also be a plain Logo value: a word becomes a JSON string (a word that is a valid JSON number becomes a number, and true/false become JSON booleans), a number becomes a JSON number, a list becomes a JSON array, and the empty list becomes null. String values are escaped as required by JSON, and numbers JSON cannot represent (infinities and NaN) become null.

Example:

?show json.make (json.object "name "Blair "tags (json.array "logo "c))
{"name":"Blair","tags":["logo","c"]}
?pr (http.post "http://example.com/people json.make (json.object "name "Blair) "Content-Type "application/json)

===

Device Specific

battery

battery

operation

The battery operation returns a list where the first value is the percent remaining in the battery and the second value is true if the battery is currently charging.

Example:

?show battery
[78 false]
?pr se [Battery:] item 1 battery
Battery: 78

goodbye

goodbye

command

goodbye closes all open files and powers off the device. If the device does not support this capability, an error is displayed.

Example:

; Safely shut down the PicoCalc
?pr [Saving workspace...]
?save "session
?goodbye

.bootsel

.bootsel

command

.bootsel closes all open files and network connections and reboots the device into its USB bootloader (BOOTSEL mode), so a new firmware image can be copied onto it. The device disconnects from Logo immediately. If the device does not support this capability, an error is displayed.

Example:

; Reboot into BOOTSEL to flash new firmware
?.bootsel

===

Appendix A: Useful Tools

The procedures presented here are for your convenience when constructing your own procedures. Some of them were defined as examples for primitives and others appear here for the first time. These procedures are in the logo archive in the release. You can copy the contents of the archive into the root directory of the device's internal storage (or onto a /sd card and copy them across). A sample startup file is also included to load these tools.

Graphics Tools

These procedures are found in the file graphics_tools.

arcr and arcl

arcr radius degrees
arc1 radius degrees

command

arcr and arcl draw right and left turn arcs, respectively. Their inputs are

  • the radius of the circle from which the arc is taken
  • the degrees of the arc (the length of the edge)

circler and circlel

circler radius
circlel radius

command

circler and circlel draw right and left turn circles with a specified radius as input.

Math Tools

These procedures are found in the file math_tools.

divisor?

divisor? number1 number2

operation

divisor? indicates (true or false) whether number1 divides evenly into number2.

Program Logic or Debugging Tools

These procedures are found in the file program_tools.

sort

sort arg list

operation

sort takes list of words and outputs them alphabetically.

===

Appendix B: Parsing

When you type a line at Logo, it recognizes the characters as words and lists, and builds a list with is Logo’s internal representation of the line. This process is called parsing. The list is similar to the list that would be output by readlist. This section will help you understand how lines are parsed.

Words

A word is made up of characters. Here are some examples of words:

  • Hello
  • x
  • 314
  • 3.14
  • 1e4
  • R2D2
  • Piglatin
  • Pig.latin
  • Pig-latin (typed as Pig\-Latin)
  • Hi there (typed as Hi\ there)
  • Who?
  • !NOW!
  • St*rs (typed as St\*rs)

Each character is an element of the word. The word Hen3ry contains six elements:

H   e   n   3   r   y

Words can contain any character and this includes alphanumeric characters, spaces, delimiters, tabs, and punctuation. Delimiters must be escaped by a backslash "\" character.

Delimiters and Spacing

A word is usually delimited only by spaces or tabs: That is, there is a space or tab before the word and a space or tab after the word; they set the word off from the rest of line. There are a few other delimiting characters:

[ ] ( ) + - * / = < > 

You need not type a space between a word and any of these characters. For example, to find out how this line is parsed:

if 1<2[print(3+4)/5][print :x+6] 

type

?to testit 
>if 1<2[print(3+4)/5][print :x+6]
>end 
?po "testit
to testit
if 1 < 2 [print (3 + 4) / 5] [print :x + 6]
end

And if you define a procedure to contain a line in the first form, you will see that Logo has converted it into the second.

To treat any of the characters mentioned above as a normal alphabetic character, put a backslash "\" before it. For example:

?print "fish\+chips
fish+chips
?print "butter\ tart
butter tart

Note that the quotation mark character (") and the colon (:not word delimiters.

You can also have an empty word, which is a word with elements. You type in the empty word by typing ".

Two delimiters are exceptions inside a quoted word: '/' and '-'. You can use them without a backslash and Logo treats them as normal characters. The '/' is convenient for file names and URLs, and '-' for hyphenated names such as HTTP header fields. For example:

?print "my/file/name
my/file/name
?print "Content-Type
Content-Type

Vertical Bars

Backslashing every delimiter one at a time is tedious when a word contains several of them. As an alternative, enclose a run of characters in vertical bars (|). Every character between the bars — including spaces, brackets, parentheses, and the infix operators — is treated as though it were an ordinary letter. The bars themselves are not part of the word.

?print "|New York|
New York
?print "|(a+b)|
(a+b)
?make "|my count| 10
?print :|my count|
10
?show count [|San Francisco| |New York|]
2

The bars are consumed when the word is read, so [|San Francisco| |New York|] is a two-element list. (Printing does not restore the bars, so such a list displays as [San Francisco New York].)

Bars may appear anywhere a word is read: bare words, quoted words ("), variable references (:), and inside lists. Within bars, backslash still works, and the only two characters that must be backslashed are the vertical bar and the backslash themselves:

?print "|a\|b|
a|b

The two notations may be mixed freely; "3\[a\]b and "|3[a]b| produce the same word.

Infix Procedures

The following characters are the names of infix procedures. You write the name between the two inputs, but Logo considers the procedures to have two inputs.

+ - * / = < > 

Brackets and Parentheses

Left bracket ”[” and right bracket ”]” indicate the start and end of a list or sublist.

[Hello there, old chap]
[x y z]
[Hello]
[[House Maison] [Window Fenetre] [Dog Chien]]
[HAL [QRZ] [Belinda Moore]]
[1 [1 2] [17 2]]

The list [Hello there, old chap] contains four elements:

  1. Hello
  2. there
  3. old
  4. chap

Note that the list [1 [1 2] [17 2]] contains only three elements, not six. The second and third elements also are lists:

  1. 1
  2. [1 2]
  3. [17 2]

The list [], a list with no elements, is an empty list. There also exists an empty word, which is a word with no elements. You type in the empty word by typing a quotation mark followed by a space or a right bracket "]". See the equal? operation in for examples of both the empty list and the empty word.

Parentheses group things in ways Logo ordinarily would not, and vary the number of inputs for certain primitives.

If the end of a Logo line is reached (that is, the Enter key is pressed) and brackets are still open, Logo will ask for additional lines of input (prompted with "~") until the brackets are closed:

?repeat 4 [print [This [is [a [test
~]]]
This [is [a [test]]] 
This [is [a [test]]] 
This [is [a [test]]] 
This [is [a [test]]] 

If Logo finds a right bracket or parenthesis for which there was no corresponding left bracket or parenthesis, Logo returns an error:

?]print "ABC
Unexpected ']'
?print 2 + 3)
Unexpected ')'

A left bracket that is never closed is an error too. Because a semicolon comments out the rest of the line, a closing bracket written after one is not seen and the list is left open:

?show [a b
[ without ]
?show [a ; b]
[ without ]

Quotation Marks and Delimiters

Normally, you have to put a backslash () before the characters [,],(,), and \ itself. But the first character after a quotation mark (") does not need to have a backslash preceding it. For example:

?print "*
*

If a delimiter occupies any position but the first one after the quotation mark, it must have a backslash preceding it. For example:

?print "****
Not enough inputs to *

The exceptions are '/' and '-', which are always treated as normal characters in a quoted word (see Delimiters and Spacing), so "my/file/name and "Content-Type are each a single word.

The only exception to the above general rule is brackets ([ ]). If you want to put a quotation mark before a bracket, you must always include a backslash between the quotation mark and the bracket. For example:

?print "[ 
You don't say what to do with [] 
?print "\[
[ 
?repeat 4 [print "]




Four empty lines are produced since the "] is recognised as an emoty word followed by the closing bracket.

The Minus Sign

The way in which the minus sign "-” is parsed is also a little strange. The problem here is that one character is used to represent two different things:

  1. as part of a number to indicate that it is negative, as in -3
  2. as a procedure of one input, called unary minus, which outputs the additive inverse of its input, as in -XCOR or -:DISTANCE
  3. as a procedure of two inputs, which outputs the difference between its first input and its second, as in 7-3 and XCOR-YCOR

The parser tries to be clever about this potential ambiguity and figure out which one was meant by the following rules:

  1. If the ”-” immediately precedes a number, and follows any delimiter except right parenthesis ”)”, the number is parsed as a negative number. This allows the following behaviour:
  • print sum 20-20 (parses as 20 minus 20)
  • print 3*-4 (parses as 3 times negative 4)
  • print (3+4)-5 (parses as 3 plus 4 minus 5)
  • first [-3 4] (outputs -3)
  1. If the ”-” immediately precedes a word or left parenthesis ”(”, and follows any delimiter except right parenthesis, it is parsed as the unary minus procedure:
  • setpos list :x -:y
  • setpos list ycor -xcor
  1. In all other cases, ”-” is parsed like the other infix characters-as a procedure with two inputs:
  • print 3-4 (parses as 3 minus 4)
  • print 3 - 4 (parses exactly like the previous example)
  • print - 3 4 (procedurally the same as the previous example)

The right-parenthesis exception in rules 1 and 2 applies only when the ”)” is directly adjacent to the ”-” with no space between them. Once whitespace separates them, the space itself counts as the delimiter, so what follows the ”-” decides:

  • print (5+3)-2 (parses as 8 minus 2 - the ”-” touches the ”)”)
  • print (5+3) -2 (parses as the two values 8 and -2 - the space before ”-” and the digit touching it make -2 a negative number)

This whitespace-sensitive reading matches established Logo convention: - glued to what follows it (but not to what precedes it) is negative or unary, while - surrounded by values on both sides is subtraction.

===

Appendix C: Useful Procedures

This Appendix contains procedures that are not primitives but are useful for various purposes. You can use these procedures as they are or modify them to suit your needs.

You can add these procedures to your startup file so they are always available when you start Logo. To do this, copy and paste the code into a file named startup and save it (save "startup) in the root directory of the device's internal storage.

Displaying Formatted Time

These procedures are for displaying the date and time in a more human-friendly format. The zeropad procedure adds a leading zero to numbers less than 10. The fdate and ftime procedures format the date and time, respectively, using zeropad to ensure that single-digit numbers are displayed with a leading zero.

to zeropad :n
  if 2 > count :n [op word "0 :n]
  op :n
end

to fdate
  op reduce [[a b] (word :a "- :b)] map "zeropad date
end

to ftime
  op reduce [[a b] (word :a ": :b)] map "zeropad time
end

WiFi Connection

This procedure connects to a WiFi network and then synchronizes the time with an NTP server. You can change the SSID, password, timezone (-5), and NTP server ("ca.pool.ntp.org) as needed.

to connect
  if not wifi? [
    wifi.connect "SSID "Password
  ]
  if (network.ntp -5 "ca.pool.ntp.org) [
    (pr [The time is] fdate ftime)
  ]
end

===

Appendix D: Error Messages

When error 35 ("I don't know how to ...") is reported at the prompt, Logo also suggests the closest primitive or procedure name if one is similar, for example Did you mean forward?.

NumberMessage
1(procedure) is already defined
2Number is too big
3(symbol) isn't a procedure
4(symbol) isn't a word
5(procedure) can't be used at toplevel
6(symbol) is a primitive
7Can't find label (symbol)
8Can't (symbol) from the editor
9(symbol) is undefined
10(procedure) didn't output to (symbol)
11I'm having trouble with the disk
12Disk full
13Can't divide by zero
14End of data
15File already exists
17File not found
18File is the wrong type
19Too few items in (list)
20No more file buffers
21Can't find a catch for (symbol)
22(symbol) not found
23Out of space
24(procedure) can't be used in a procedure
25(symbol) is not true or false
26Pausing...
27You're at toplevel
28Stopped!
29Not enough inputs to (procedure)
30Too many inputs to (procedure)
31Too much inside parenthesis
32Too few items in (list)
33Can only do that inside a procedure
34Turtle out of bounds
35I don't know how to (symbol)
36(symbol) has no value
37) without (
38I don't know what to do with (symbol)
39] without [
40Disk is write-protected
41(procedure) doesn't like (symbol) as input
42(procedure) didn't output
43I can't run (procedure) on this device
44No file selected
45File (file) not open
46File (file) already open
47File position out of range
48Device unavailable
50Already dribbling
52Device (device) in use
53File (file) too big
55Subdirectory not found for (directory)
56Subdirectory (directory) not empty
57Can't open ip address and port (ip address and port)
58I lost the network connection
59Network connection not open
60Network error occurred
61Can't use (symbol) as a file or network connection
62Invalid IP address or port (ip address and port)
63Network connection already open
64Can't (symbol) on a network connection
65Network timeout occurred
66Invalid network operation
67Too many nested operations
68I don't know about (procedure)
69There is no SD card
70Backup file must be on the SD card
71Backup file is not valid for this device
72[ without ]
!!! LOGO SYSTEM BUG !!! Should not occur. Please let me know.

===

Appendix E: Colour Palette for Pico Logo

This is the colour palette for Pico Logo. The palette contains 256 colour numbers. The standard palette includes a range of colours across hues and includes greyscale colours.

The first 16 colour numbers are the used by the text screen. Each character on the text screen has a foreground colour and a background colour, each of which is a colour number. The colour used for the foreground and background can be changed using settextcolor. The default foreground colour number is 3 (white) and the default background colour number is 4 (dark background).

These colour numbers are assigned to the following purposes. You can change the colour stored in these colour numbers to customise the the text screen and editor's appearance:

Colour NumberPurpose
0Text foreground (0%)
1Text foreground (33%)
2Text foreground (66%)
3Text foreground (100%)
4Text background
5Error messages
6Strings ("word)
7Commands
8Procedure name (word after to)
9Numbers
10Comments
11Variables (:name)
12Keywords (to, end)
13Bracket depth 1
14Bracket depth 2
15Bracket depth 3

The following 160 colour numbers are the default palette for Pico Logo, and changing these colour numbers should be avoided.

Colour numbers 176 through 247 are unallocated and can be used for your own purposes. You can change the colour stored in these colour numbers to create your own palette.

Colour numbers 248 through 253 hold the primary and secondary colours. Changing this range of colour numbers should be avoided.

Colour number 254 is used as the default pen colour. Colour number 255 contains the current background colour used on the graphics screen and is set using setbg.

Colour Palette for Pico Logo