TEACH PROGLECT5 Aaron Sloman Oct 1998 Revised: 31 May 2009 Revision and more detail of previously presented information on Pop-11 See TEACH * PROGLECT1 TEACH * PROGLECT2 TEACH * PROGLECT3 TEACH * PROGLECT4 CONTENTS -- A few reminders first -- What's involved in learning pop-11 -- Learn the syntax of Pop-11 -- Learn the semantics of Pop-11 -- -- Compile time meaning -- -- Run time meaning -- The Pop-11 "data stack" or "user stack" -- Putting things on the stack -- Removing things from the stack -- "=>" and the stack -- Using the stack to create structures -- -- Uses of predicates -- How procedures run -- Packaging instructions into named procedures -- The "little man with script" model of procedure invocation -- Control jumps in a procedure -- A procedure call and the stack -- Infix operators -- Variables and how they work -- -- Different uses of the assignment arrow -- -- Invoking updaters -- Pop-11 data types -- More on Pop11 control structures -- -- General purpose loop formats: -- -- Data related loop formats: -- A few reminders first ---------------------------------------------- SPEEDING UP VED'S INITIALISATION If VED starts up too slowly for you Get rid of the command to start up menus automatically, in your vedinit.p define vedinit(); ;;; Comment this out if you don't want the menus (use "ENTER menu" instead) vedinput(veddo(%'menu'%)) enddefine; LATER You can get the menus going when you want them, with the command: ENTER menu USING MAIL INSIDE VED. See TEACH EMAIL if you need revision on the use of mail in VED. MINI PROJECTS. SEE TEACH POP11_PROJECT -- What's involved in learning pop-11 --------------------------------- -- Learn the syntax of Pop-11 ----------------------------------------- Which forms of expression are "legal" What sorts of compile time errors occur because of wrong syntax Later: how you can extend the syntax by defining macros or syntax words. E.g. define :form .... See HELP * DEFINE_FORM -- Learn the semantics of Pop-11 -------------------------------------- What the various formats mean -- -- Compile time meaning Variable declarations Different types of identifiers (e.g. infix operators, macros, syntax words) Procedure definitions "Top level" Pop-11 commands Use of word quotes, string quotes, list expressions, vector expressions For experts: The use of sections can "protect" bits of code global lvars can do this in the context of a file. Compiler directives (compile_mode) -- -- Run time meaning The Pop-11 virtual machine: the objects and processes -- The Pop-11 "data stack" or "user stack" ---------------------------- The stack is both a source of power and a source of problems. Similar to the programming language Forth. Uses of the "data stack" ("user stack") for temporary storage and communication between sub-processes include the following: o Arguments passed to procedures from other procedures or "top level" commands o Results produced by procedures when they finish are left on the stack. They can then be used by the calling procedure, or "top level" command, e.g. to print the result. o Items stored temporarily for the purpose of building a complex data-structure, e.g. list or vector or array This uses syntax like the following in list and vector expressions: [% .... % ^... ^^...] {% .... % ^... ^^...} Examples below. See TEACH * STACK for more details. -- Putting things on the stack When any Pop-11 instruction or expression is evaluated, if there is no result the stack is unchanged. If there are any results then they are all left on the stack, in an order that can be controlled by the header of a procedure with output local variables. E.g. define foo(...) -> (r1, r2, r3); means that when foo finishes it puts three results on the stack, first r1, then r2, then r3. Those should be variables that are given values when the procedure runs. The "->" is NOT an assignment arrow. Most procedures return only one result, including most of the arithmetic procedures, e.g. "+", *". However the integer division operator "//" returns two results, the remainder and the divisor: 10//3 => ** 1 3 Contrast 10/3.0 => ** 3.33333 A collection of items can be put on the stack in a single expression made of sub-expressions separated by commas: 1, 2, 3+5, "cat", [a b] <> [c d] => ** 1 2 8 cat [a b c d] The same items in a different order: "cat", [a b] <> [c d], 1, 2, 3+5 => If a variable has a value, simply using that variable puts its value on the stack. vars list3 = [silly example]; list3 => Using it three times puts THE SAME THING on the stack three times list3, list3, list3 => Notice that the value of the variable is NOT COPIED each time it is used. If the value is a complex object, then the variable contains a "pointer" to that object and the pointer to that very object, not a copy, is put on the stack. The object remains in Pop-11's main re-usable memory space, known as "the heap" (which is different for each user, and which is destroyed every time you leave Pop-11). -- Removing things from the stack One common way of removing something from the stack is to use the assignment arrow to assign something to a variable. vars x; NB the next three lines must be marked and loaded in one go, as VED removes stuff left on the stack between commands: 3; ;;; puts three on the stack -> x; ;;; assigns it to x => ;;; see what's left ** NB the next three lines must be marked and loaded in one go, as VED removes stuff left on the stack between commands: "a", "b", 3, 4, 5; ;;; put five things on the stack -> x; ;;; assign one to x: removes the last item => ;;; see what's left ** a b 3 4 Try again with different things on the stack Another way to remove something from the stack is to run a procedure. Procedures take the arguments they need, i.e. the values for their input variables, off the stack, and put their results back. So procedures like "+", "-", "*", matches and issubstring take two things off the stack and return one thing: 1, 2, +() => ;;; actually "+" does not need "()" ** 3 99, 55 * => That is the same as 99 * 55 => issubstring("def", "define")=> ;;; returns start of substring ** 1 issubstring("fine", "define")=> ** 3 If there are not enough things on the stack you will get a mishap message, e.g. "*" needs two arguments: 3 * => ;;; MISHAP - ste: STACK EMPTY (missing argument? missing result?) ;;; FILE : /bham/common/com/packages/poplog/local/teach/proglect5 LINE NUMBER: 244 ;;; DOING : mishap * .... So you can put five things on the stack, call a procedure that takes two and returns one, and end up with four 1, 2, 3, 4, 5, * => ** 1 2 3 20 -- "=>" and the stack Warning: outside procedures "=>" prints everything on the stack. It also clears the stack. Inside procedures it prints only the top item on the stack, and removes it from the stack. If there's nothing on the stack, then outside a procedure "=>" prints just "**" followed by nothing => ** Inside a procedure define test(); => enddefine; test() => ;;; MISHAP - ste: STACK EMPTY (missing argument? missing result?) NB: The pretty print arrow "==>" ALWAYS expects at least one thing to be on the stack, and it always prints exactly ONE thing, which it removes from the stack. [% repeat 5 times [% for x from 1 to 10 do 300*x endfor %] endrepeat %] ==> Explain all the things put on the stack and removed there. E.g. inside [% ... %] things can be put on the stack, then at the end of the list expression they are all removed and put in a list, and then the list (i.e. a pointer to the list) is put on the stack. How many stack operations were there in the above? 300 * x involves two additions, two removals, then one addition In the inner loop, that's done 10 times, creating 10 items. Then the enclosing list brackets remove all 10 items and put one back. That's done 5 times, putting 5 items on the stack. Etc. Finally ==> removes one item, and prints it, the list of lists. -- Using the stack to create structures ------------------------------- You need to understand the uses of the stack to create structures, e.g. by having a loop inside list brackets, or by putting a procedure call inside list brackets. vars x; [% for x from 3 by 3 to 66 do x endfor %] => vars list = [ cat dog 5 7 99 mouse elephant 4 2 1 pink]; define stack_all_of(type, list); lvars item; for item in list do if type(item) then item endif endfor enddefine; stack_all_of(isword, list) => stack_all_of(isnumber, list) => [% stack_all_of(isword, list) %] => [% stack_all_of(isnumber, list) %] => define istiny(x); isnumber(x) and x < 5 enddefine; [% stack_all_of(istiny, list) %] => The procedures istiny, isword, isnumber are PREDICATES. If applied to an object a predicate produces the result true or false. Some predicates are applied to two or more things, and are called RELATIONS, e.g. =, >, <, matches These take two things, and produce a true or false result. -- -- Uses of predicates Predicates can be used to create conditions, i.e. expressions that evaluate to TRUE or FALSE. (In Pop-11 any non-false object counts as a TRUE value for a conditional). Occurrences of conditions include the following contexts. In conditional expressions: if then elseif then unless then elseunless then In loop headers: between while and do while do between until and do until do Inside loops, to control the loop behaviour: quitif( ) quitunless( ) nextif( ) nextunless( ) Anywhere: returnif( ) -- How procedures run ------------------------------------------------- In order to understand Pop-11 you need to understand how procedures work. This includes knowing all of the following: What happens when a procedure starts up including assignments to input local variables What happens when a procedure finishes including saving values of output locals How local variables work: "vars" and "lvars" How the instructions in the procedure are obeyed, i.e. which ones are obeyed in which order. For instance where there are conditional expressions only a subset of the instructions will be obeyed, depending on the result of evaluating the condition. How a procedure invokes other procedures, including giving it arguments. What happens when the invoked procedure "returns", i.e. finishes, possibly leaving one or more results on the stack. How abnormal exits work (for experts only: see HELP * CONTROL) See TEACH * STACK, TEACH * DEFINE, TEACH * PRIMER For experts: REF * PROCEDURE -- Packaging instructions into named procedures ----------------------- A procedure definition uses special syntax to express all the above ideas. In different languages different syntax may be used. Not all languages allow the same ideas to be expressed. In Pop-11 this is the basic procedure definition format. define name(arg1, arg2 ...) -> (output1, output2...); declarations (including nested procedure definitions) actions enddefine; The declarations and actions can be arbitrarily intermingled. Some of the actions will invoke other procedures. Some will use special syntax forms to control which actions are done and in which order. See TEACH DEFINE, HELP DEFINE Procedure calls assume automatic "return" to caller action1; do_stuff(x,y,z); ;;; automatically returns here action2; -- The "little man with script" model of procedure invocation --------- Each procedure corresponds to a script, which can be copied. Each time a procedure is invoked a "little man" inside the computer is created (or fetched from a store room) given a copy of the script, and told to follow the instructions. If there's a call to another procedure the little man puts the arguments on the stack before calling the procedure, then waits for the next little man to finish. Just before each little man finishes, he puts any "results" (values of output locals) on the stack, gives a "wake up" signal to the little man who is waiting for him, and then goes back to the store room. Any lexical local variables are handled by using special spaces on the copy of the script. Other local variables ("vars" variables) use more complex processes. Thus at any one time there can be a "stack" of little men with half completed scripts, each waiting for the next one to finish, with the last little man actually doing something with his script. (Some people see this stack growing upwards, some downwards.) -- Control jumps in a procedure --------------------------------------- Various kinds of jumps and abnormal exits goto label (not recommended) For experts: go_on switchon For exiting from or restarting loops. In each case the (N) is optional and defaults to 1. N must be a nonnegative integer, not an expression that evaluates to an intenger. quitloop(N) exit from the Nth enclosing loop nextloop(N) restart the Nth enclosing loop quitif()(N) equivalent to if then quitloop(N) endif nextif()(N) equivalent to if then nextloop(N) endif quitunless()(N) equivalent to unless then quitloop(N) endunless nextunless()(N) equivalent to unless then nextloop(N) endunless For exiting from the current procedure return() return() returnif() () equivalent to if then return() endif returnunless() () equivalent to unless then return() endunless When a procedure finishes: What happens to local vars (dynamic "permanent" local variables) Previous values restored What happens to local lvars (lexical local variables) Variable no longer exists on exit, unless a "closure" is created (for experts only). Abnormal exits: exitto(procedure) exitfrom(procedure) and others, chain, chainto, chainfrom, catch, throw etc. See HELP * CONTROL also suspend, and resume, with processes HELP * PROCESS Interrupt is equivalent to exitto(some top level procedure) (Use of Popready to control interrupts: HELP * POPREADY) -- A procedure call and the stack ------------------------------------- silly(x, sumsq(3,4), 99) Means: 1. push onto the stack all of the following the value of "x", the result of sumsq(3,4), 99 2. then run the procedure called SILLY Getting the result of SUMSQ(3,4) itself can be expanded in similar fashion, so the whole expression silly(x, sumsq(3,4), 99) translates to 1. push the value of x onto the stack 2. push 3 onto the stack 3. push 4 onto the stack 4. call the procedure called "sumsq" (It will take off two things and push its result onto the stack) 5. push 99 onto the stack 6. call the procedure called "silly" Notice that the thing mentioned first is actually invoked last. Compare the language FORTH Pop-11 allows a "dot" notation, which some people like to use x, 3, 4 .sumsq, 99 .silly => That is equivalent to: silly(x, sumsq(3,4), 99) => -- Infix operators ---------------------------------------------------- Infix operators are just names for procedures. 3 + 4 => This is equivalent to +(3, 4)=> I.e. push 3 push 4 call + (which removes 3, adn 4 and pushes its result) call => The precedence of an operator determines the sequence of operations. Parentheses can override precedence: Compare 3 + 4 * 5 => (3 + 4) * 5 => Don't confuse use of parentheses to control precedence and use of parentheses to invoke procedures "doit brackets", with our without inputs. -- Variables and how they work ---------------------------------------- TEACH * VARS, TEACH * VARS_AND_LVARS words, identifiers and values How assignment gives a word a value, via the stack -> variable; The Pop-11 dictionary and its role at compile time and run time (valof, the matcher) -- -- Different uses of the assignment arrow Assigning to a variable 3 -> x; Multiple assignments: 3, 4, 5 -> (x, y, z); Initialised declarations include an assignment vars x = 3; -- -- Invoking updaters The use of the assignment arrow to invoke updaters of procedures, e.g. vars list = [a b c d] "cat" -> hd(list); list => [on a mat] -> tl(list); list => vars vec = {1 2 3 [4 5] a cat}; vec => subscr(5, vec) => 33 -> subscr(5, vec); subscr(5, vec) => See HELP * UPDATER -- Pop-11 data types -------------------------------------------------- The Primer gives an overview, and REF DATA gives a lot more detail. Pop-11 has many kinds of "data-structures" for storing information: o provided by the user o created by the program o read in by the program while it is running, e.g. from other programs, sensors, etc. Types of data include numbers (various kinds), words, strings, lists, vectors, properties, and many more Some data-types are primitive (built in to Pop-11 at a low level). Others are derived. E.g. lists are a derived datatype, created from pairs, which are two-element records. If lists had not been in Pop-11 we could have invented them, and defined the syntax. Pop-11 databases use a derived data type built on top of lists. Arrays are a derived datatype, created from procedures and vectors, though it would not be so easy for users to implement them. For this course a subset of data types will suffice. (See TEACH * POPCORE, TEACH * PRIMER) (Experts see REF DATA) -- More on Pop11 control structures ----------------------------------- There are many sorts of "control structures" Sequences of instructions action1; action2; ...... Conditional instructions if condition then action elseif Multi-branch conditionals if condition1 then action1 elseif condition2 then action2 elseif .... else ... endif Loops of various kinds -- -- General purpose loop formats: repeat .... endrepeat while condition do action endwhile until condition do action enduntil -- -- Data related loop formats: for x from 1 to 75 do action(x) endfor for x in list do action(x) endfor foreach pattern in database do action endforeach forevery patternlist in database do action endforevery ... and several more. See HELP * LOOPS, HELP * CONTROL REF * using_subscriptor To be revised and continued. --- $poplocal/local/teach/proglect5 --- Copyright University of Birmingham 1998. All rights reserved. ------