apoo-2.2/0000750000076600000240000000000010745416720011347 5ustar rvrdialoutapoo-2.2/apoo0000750000076600000240000000017510745416725012243 0ustar rvrdialout#!/bin/bash #change this line to current directory of Apoo files DIR=/usr/lib/apoo /usr/bin/python $DIR/interface.py $* apoo-2.2/apoo.master0000640000076600000240000000016610745416725013533 0ustar rvrdialout#!/bin/bash #change this line to current directory of Apoo files DIR=/usr/lib/apoo %python% $DIR/interface.py $* apoo-2.2/constants.py0000640000076600000240000000707510745416725013754 0ustar rvrdialout#!/usr/bin/python # -*- coding: utf-8 -*- """ contants for Apoo Copyright (C) 1998-2003 Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @author: Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt """ import exceptions __version = "$Id: constants.py,v 1.27 2006-04-15 22:10:24 rvr Exp $" False = 0 True = 1 class vpuError(Exception): pass class EndOfProgram(vpuError): def __init__(self): self.message = 'End Of Program' self.colour = 'green' class OutOfMemory(vpuError): def __init__(self,add): self.message = 'Out of Memory' self.add = add self.colour = 'red' class OutOfProgram(vpuError): def __init__(self): self.message = 'Out of Program' self.colour = 'red' class LabelError(vpuError): def __init__(self,line = 0): self.message = 'Label Error' self.line = line self.colour = 'red' class LabelNameError(vpuError): def __init__(self,line = 0): self.message = 'Label Name Error' self.line = line self.colour = 'red' class TooManySteps(vpuError): def __init__(self, num): self.message = 'Probably an infinite loop' self.num = num self.colour = 'red' class vpuLoadError(vpuError): def __init__(self, line): self.line = line class BadArgs(vpuLoadError): def __init__(self,line): self.message = 'Wrong number of arguments' vpuLoadError.__init__(self,line) class WrongArg(vpuLoadError): def __init__(self,line): self.message = 'Wrong argument' vpuLoadError.__init__(self,line) class NotInt(vpuLoadError): def __init__(self,line): self.message = 'Integer expected' vpuLoadError.__init__(self,line) class IllInst(vpuLoadError): def __init__(self,line): self.message = 'Illegal Instruction' vpuLoadError.__init__(self,line) class IllOperand(vpuLoadError): def __init__(self,line): self.message = 'Illegal Operand' vpuLoadError.__init__(self,line) class IllReg(vpuLoadError): def __init__(self,line): self.message = 'Illegal Register' vpuLoadError.__init__(self,line) class FileError(vpuError): def __init__(self,line=0): self.message = 'File Error' class MemoryUnderflow(vpuError): def __init__(self,add): self.message = 'Memory Underflow' self.add = add self.colour = 'red' # zero arg, nonreg, reg, reg reg, nonreg reg, reg nonreg, specials inst = (['rtn','halt','nop'], # zero arg ['jsr','jump'], # nonreg ['inc','dec','zero','not','jumpi','push','pop'], #reg ['storei','loadi','storer','add','sub','mul','div','mod', 'and','or','xor'], # reg reg ['load','loadn','loado'], # nonreg reg ['store','jzero','jnzero','jpos','jneg','storeo'], # reg nonreg ['mem','const','string','equ']) #specials apoo-2.2/docs/0000750000076600000240000000000010745416720012277 5ustar rvrdialoutapoo-2.2/docs/help_apoo.txt0000640000076600000240000000531010745416725015013 0ustar rvrdialout ------------------------------------------------------------------- Apoo Workbench Copyright (C) 1998-2002 Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt ------------------------------------------------------------------- The Apoo Workbench is an environment to monitoring the execution of a Virtual Processor Unit. During the execution of a program, it shows the contents of the program counter, registers and memory data. The program in memory is displayed in an Assembly language (not in a machine language). As is usual with processor units emulators, Apoo has two memory segments: the program-segment and the data-segment. In this way, both addresses for program instructions and data will begin in 0. The Apoo Workbench allows also the editing/saving of the text program, providing an easy way to write/edit/debug/execute Apoo assembly programs. Execution: --------- To execute a program in the Apoo Virtual Processor Unit you must first or: - enter in Edit Mode and write its instructions - open a text file with its code After that, you can Load it; if a "parsing error" occurs, enter edit mode and correct it; the interface will show the text line in which the error occurred. When the program is loaded (in memory) you can execute it in three ways: - Run: will execute all the instructions - Step: will execute the next instruction and the values of the program counter, registers and memory data will be updated; the next instruction line, if exists, will have the background white - Cont: will execute instructions until the next breakpoint In an instruction line, you can set/clear a breakpoint: - to set a breakpoint: Press -Button1 in that line (the foreground will become green) - to clear breakpoint: Press -Button2 (the foreground will become black) The button labeled Clear can be used to clear all breakpoints Edit Mode: --------- In edit mode you can change the text code of a program or create a new one. To enter Edit Mode press the Edit button or New button. After editing you can Save or SaveAs the current edited text. You leave Edit Mode by loading the program (Load button) or opening a new file. The following emacs-like commands are implemented: kill-line yank kill-region w copy-region-as-kill set-mark-command beginning-of-line end-of-line beginning-of-buffer end-of-buffer deletes the character to the right of the insertion cursor. ----------------------------- The End --------------------------------- apoo-2.2/docs/help_assembly.txt0000640000076600000240000002315510745416725015703 0ustar rvrdialout -------------------------------------------------------------------------- Apoo Assembly Language --------------------------------------------------------------------------- All memory cells and registers have 32 bits. Registers: R0,R1,R2,R3,R4,R5,R6,R7 --------- Memory Data: ----------- The size of the RAM is predefined (e.g. 1K) and divided into two areas: static memory and system stack. The static memory, begins at address 0 and it is allocated when a Apoo program is loaded. Static memory cells can be reserved in in two ways, using the following pseudo-instructions: Pseudo-instructions: ------------------- Meaning ------------------------------------------------- mem n reserves n memory addresses ------------------------------------------------- Label: const n2 contents of memory address const n1 Label is n1, of Label+1 is n2 . . . ni can be a character 'c' ------------------------------------------------------------------ Label: equ n Allows a symbolic name for a number ------------------------------------------------------------------- Label: string "seqNWSCharacteres" Allocates memory addresses and set them to the correspondent characters ASCII codes. The characters cannot be whitespaces: use \s for space \t for tab and \n for newline ---------------------------------------------------------------------- Label is any string begining with a letter and containing only letters and digits with the exception of legal register names. If exists, must begin in the first column of a line NOTE: Every memory address refered, must have been reserved by one of the previous pseudo-instructions. E.g. the instruction "load 3 R2", will cause an "Out of Memory" error, if at least "mem 3" or three "const" pseudo-instructions were not given... If a "equ" value is used as a memory address, that address must be already reserved or be a known memory-mapped instruction. The "string" argument must be quoted and is converted to a sequence of ascii codes ending with 0. ----------------------------------------------------------------------- System Stack: ------------ The system stack occupies the rest of the RAM (growing for higher addresses). Since Apoo version 3.0 it can be used in an advanced way to implement activation records. However in can be used in a simpler way to implement subroutines. We can only push a value to the Stack and pop a value from it (the one in the top of the Stack). It is used by the instructions jsr and rtn. It can be manipulated by means of the push and pop instructions. ----------------------------------------------------------------------- Memory mapped: ------------- It is possible to associate to special memory positions a special effect. Currently this is used for input/output: store R0 50000 # writes character with ascii code R0%256 load 50000 R0 # loads R0 with 0 (do nothing) store R0 50001 # writes the contents of R0 as integer load 50001 R0 # reads an integer and stores it in R0 store R0 50010 # writes a CR load 50010 R0 # loads R0 with 0 (do nothing) Instruction form: ---------------- Operation Label is any string of letters or digits; if exists, must begin in the first column of a line Comments: -------- A line beginnig with # will be ignored by the parser; so it can be used to write comments of the program Basic Instruction Set: --------------------- -------------------------------------------------------------------------- Operation Operand1 Operand2 Meanning -------------------------------------------------------------------------- load Mem Ri loads contents of memory address Mem into register Ri; Mem can be a label -------------------------------------------------------------------------- loadn Num Ri loads number Num into register Ri; Num can be a label -------------------------------------------------------------------------- loadi Ri Rj loads contents of memory which address is the contents of Ri into Rj (indirect load) -------------------------------------------------------------------------- store Ri Mem stores contents of Ri at memory address Mem; Mem can be a label -------------------------------------------------------------------------- storer Ri Rj stores contents of Ri into Rj -------------------------------------------------------------------------- storei Ri Rj stores contents of Ri into at memory address, which is the contents of Rj -------------------------------------------------------------------------- add Ri Rj add contents of register Ri to contents of register Rj, and stores into Rj (Rj=Ri+Rj) -------------------------------------------------------------------------- sub Ri Rj subtracts contents of register Rj from contents of register Rj and stores into Rj (Rj=Ri-Rj) -------------------------------------------------------------------------- mul Ri Rj multiplies contents of register Ri and contents of register Rj, and stores into Rj (Rj=Ri*Rj) -------------------------------------------------------------------------- div Ri Rj stores into Rj the quotient of integer division of contents register Ri by the contents of register Rj, and stores into Rj (Rj=Ri/Rj) -------------------------------------------------------------------------- mod Ri Rj stores into Rj the rest of integer division of contents of register Ri by the contents of register Rj, and stores into Rj (Rj=Ri%Rj) -------------------------------------------------------------------------- zero Ri the contents of Ri becomes 0 (Ri=0) -------------------------------------------------------------------------- inc Ri increments by 1 the contents of Ri -------------------------------------------------------------------------- dec Ri decrements by 1 the contents of Ri -------------------------------------------------------------------------- jump Addr jumps to instruction address Addr; Addr can be a Label -------------------------------------------------------------------------- jzero Ri Addr jumps to instruction address Addr, if contents of Ri is zero; Addr can be a Label -------------------------------------------------------------------------- jpos Ri Addr jumps to instruction address Addr, if contents of Ri is positiv; Addr can be a Label -------------------------------------------------------------------------- jneg Ri Addr jumps to instruction address Addr, if contents of Ri is negativ -------------------------------------------------------------------------- jnzero Ri Addr jumps to instruction address Addr, if contents of Ri is different from zero --------------------------------------------------------------------------- jsr Addr pushes the PC into the stack and jumps to instruction address Addr -------------------------------------------------------------------------- rtn pops an address from the stack into the PC -------------------------------------------------------------------------- push Ri pushes the contents of Ri into the system stack -------------------------------------------------------------------------- pop Ri pops at element from the system stack into Ri -------------------------------------------------------------------------- halt stops execution; Every program must have this instruction in order to end properly; otherwise an 'Out of Program' error will occur -------------------------------------------------------------------------- Activation Records Management ---------------------------- There are two programmable registers to address the system stack: stack register and frame register. They correspond to the last two registers of a Apoo vpu configuration, Rn-1 and Rn-2, but are aliased to rs and rf, respectively. The stack register rs contains the address of the last stack memory cell (or -1 if no static memory is allocated). The instructions jsr, rtn, push and pop manipulates the stack in the usual way. Besides that, the contents of the stack register can be manipulated as any other register. The frame register can be used for the implementation of local information (on the system stack). It contents should be the first stack address of the current activation record. Like the stack register it can be manipulated as any other register, but it is also used in two special instructions: storeo and loado. - storeo Ri Num: stores the contents of register Ri at memory address (rf) + Num, where Num is an integer. - loadeo Num Ri: loads the contents of memory address (rf) + Num into register Ri, where Num is an integer. In both instructions, if Num is non negative it should correspond to local memory and if it is negative, possibly corresponds to arguments of a subroutine call. ------------------------- The End --------------------------------------- apoo-2.2/docs/help_tester.txt0000750000076600000240000000326610745416725015375 0ustar rvrdialout------------------------------------------------------------------- Apoo Tester ------------------------------------------------------------------- The Apoo Tester is an environment to monitoring the execution of a Virtual Processor Unit. During the execution of a program, it shows the contents of the program counter, registers and memory data. The program in memory is displayed in an Assembly language (not in a machine language). As is usual with processor units emulators, Apoo has two memory segments: the program-segment and the data-segment. In this way, both addresses for program instructions and data will begin in 0. Execution: --------- When the Tester is called with a program file it tries to load and run it. If it fails it will display the error in the message line. If a "parsing error" occurs, during "Load" the interface will show the text line in which the error occurred. When the program is loaded (in memory) you can execute it in three ways: - Run: will execute all the instructions - Step: will execute the next instruction and the values of the program counter, registers and memory data will be updated; the next instruction line, if exists, will have the background white - Cont: will execute instructions until the next break point You may set or clear a breakpoint in an instruction by double-clicking (with the mouse) on its line address number. The button labeled Clear can be used to clear all breakpoints. Exit ---- The Apoo Tester will not terminate until the caller terminates. ------------------------------------------------------------------- (C) 1998 Rogerio Reis, Nelma Moreira {rvr,nam}@ncc.up.pt apoo-2.2/examples/0000750000076600000240000000000010745416720013165 5ustar rvrdialoutapoo-2.2/examples/abs.apoo0000640000076600000240000000022710745416725014621 0ustar rvrdialout# # Implements f(x)=|x| # x: const -11 fx: mem 1 load x r1 jpos r1 fim jzero r1 fim loadn -1 r2 mul r2 r1 fim: store r1 fx halt apoo-2.2/examples/fact.apoo0000640000076600000240000000032110745416725014764 0ustar rvrdialout# # fact(n) if n==0 then 1 else fact(n-1)*n # n: const 5 fn: mem 1 load n r1 jsr fact store r1 fn halt fact: jzero r1 fim push r1 dec r1 jsr fact pop r2 mul r2 r1 rtn fim: loadn 1 r1 rtn apoo-2.2/examples/fact2.apoo0000640000076600000240000000112410745416725015050 0ustar rvrdialout jsr main halt factorial: push rf storer rs rf loado -2 r3 loadn 0 r2 sub r3 r2 jnzero r2 L0 loadn 1 r2 storer r2 r0 pop rf rtn L0: loado -2 r4 loadn 1 r3 sub r4 r3 push r3 jsr factorial loadn 1 r3 sub rs r3 storer r3 rs storer r0 r3 loado -2 r2 mul r3 r2 storer r2 r0 pop rf rtn pop rf rtn main: push rf storer rs rf loadn 2 r2 add r2 rs load 50001 r1 storeo r1 2 loado 2 r2 push r2 jsr factorial loadn 1 r2 sub rs r2 storer r2 rs storeo r0 1 loado 1 r2 store r2 50001 loadn 10 r2 store r2 50000 loadn 2 r2 sub rs r2 storer r2 rs pop rf rtn apoo-2.2/examples/fib.apoo0000640000076600000240000000052010745416725014610 0ustar rvrdialout# # fib(n)=if(n==0) or (n==1) n else fib(n-1)+fib(n-2) # n: const 6 fn: mem 1 load n r1 jsr fib store r2 fn halt # r1=n,r2=fib(n),r3=auxiliar fib: jzero r1 fim storer r1 r3 dec r3 jzero r3 fim storer r3 r1 push r1 jsr fib pop r1 dec r1 push r2 jsr fib pop r1 add r1 r2 rtn fim: storer r1 r2 rtn apoo-2.2/examples/fun.apoo0000640000076600000240000000047010745416725014644 0ustar rvrdialout m8: mem 1 loadn 1 R31 store R31 m8 loadn 2 R31 load m8 R30 push R30 push R31 jsr F0 pop R31 pop R30 store R30 m8 store R31 m8 halt F0: pop R31 m0: mem 1 pop R30 store R30 m0 push R31 m4: mem 1 loadn 3 R31 store R31 m4 load m4 R31 load m0 R30 add R30 R31 pop R30 push R31 push R30 rtn apoo-2.2/examples/funcx2y.apoo0000640000076600000240000000030410745416725015446 0ustar rvrdialoutx: const -6 y: const -5 func: mem 1 load x R0 load y R1 storer R1 R2 sub R0 R2 jneg R2 cont mul R0 R0 mul R1 R0 store R0 func halt cont: loadn 5 R3 sub R3 R1 store R1 func halt apoo-2.2/examples/ifx1.apoo0000640000076600000240000000024310745416725014721 0ustar rvrdialout# # Conditional test # if(x==1) y=0;else x=2 #R1=x; R2=y #R4 auxiliar loadn 1 R4 sub R1 R4 jzero R4 y0 x2: loadn 2 R1 jump fim y0: zero R2 fim: halt apoo-2.2/examples/ln.apoo0000640000076600000240000000013010745416725014456 0ustar rvrdialout# Example: adds 3+4+5 # loadn 3 R1 loadn 4 R2 loadn 5 R3 add R1 R2 add R2 R3 apoo-2.2/examples/ln2.apoo0000640000076600000240000000061610745416725014551 0ustar rvrdialout# # Example: adds 3,4 and 5 using indirect loading # R5 points to the first value # ini: const 3 const 4 const 5 res: mem 3 loadn ini R5 loadi R5 R1 inc R5 loadi R5 R2 inc R5 loadi R5 R3 add R1 R2 add R2 R3 store R3 res halt apoo-2.2/examples/max.apoo0000640000076600000240000000100610745416725014635 0ustar rvrdialout# maximum of a sequence of N values N: const 10 val: const 7 const 8 const 20 const 43 const 15 const 70 const 18 const 71 const 52 const 83 const 1 MAX: mem 1 #R4=maximum; R2=index load N R1 loadn val R2 loadi R2 R4 loop: inc R2 dec R1 jzero R1 cont #puts the next value in R3 loadi R2 R3 # copy before comparing with max storer R3 R5 sub R4 R5 # if R4-R5 > 0 continue jpos R5 loop #max gets a new value storer R3 R4 jump loop cont: store R4 MAX halt apoo-2.2/examples/mems.apoo0000640000076600000240000000007310745416725015014 0ustar rvrdialouta: mem 3 b: mem 4 c: mem 5 d: const 5 loadn 7 R1 halt apoo-2.2/examples/push.apoo0000640000076600000240000000005310745416725015030 0ustar rvrdialout loadn 111111 r1 push r1 pop r2 halt apoo-2.2/examples/sti.apoo0000640000076600000240000000013010745416725014644 0ustar rvrdialout# # Indirect store # data: const 3 loadn data R2 loadn 6 R1 storei R1 R2 halt apoo-2.2/examples/submax.apoo0000640000076600000240000000105310745416725015351 0ustar rvrdialout# # Subroutine for Maximum # N: const 10 val: const 7 const 8 const 20 const 43 const 15 const 70 const 18 const 71 const 52 const 83 const 1 MAX: mem 1 #R4=maximum; R2=index load N R1 loadn val R2 #R1=number of elements #R2=first element jsr max store R4 MAX halt max: loadi R2 R4 loop: inc R2 dec R1 jzero R1 cont #puts the next value in R3 loadi R2 R3 #copy for test with maximum storer R3 R5 sub R4 R5 # if R4-R5 > 0 continue jpos R5 loop #max gets a new value storer R3 R4 jump loop cont: rtn apoo-2.2/examples/subsoma.apoo0000640000076600000240000000033410745416725015524 0ustar rvrdialoutvalues: const 3 const 4 const 5 n: const 3 res: mem 1 jsr ini halt ini: zero R4 loadn values R1 load n R2 rtn loop: jzero R2 end loadi R1 R4 add R4 R3 dec R2 inc R1 jump loop end: store R3 res apoo-2.2/examples/t1.apoo0000640000076600000240000000023610745416725014400 0ustar rvrdialoutx: const -1 fx: mem 1 load x R0 jpos R0 dois storer R0 R1 mul R0 R1 store R1 fx jump fim dois: loadn 5 R1 add R0 R1 store R1 fx fim: halt apoo-2.2/examples/t1.tutor0000640000076600000240000000041310745416725014614 0ustar rvrdialout# <- comments load value 20 # constants labels # memory labels #mem [label:num[,num]*]* [label;size]* initial x:-1 fx;1 value 20 # exec value 30 # final fx:1 value 30 end # #init x:-3 #value 5 #exec #value 10 #final fx:2 #value 15 #endapoo-2.2/examples/test-mm.apoo0000640000076600000240000000020410745416725015435 0ustar rvrdialout loadn 97 R0 store R0 50000 store R0 50010 store R0 50001 store R0 50010 load 50001 R0 store R0 50001 store R0 50010 halt apoo-2.2/examples/test-rfrs.apoo0000640000076600000240000000101510745416725016001 0ustar rvrdialoutn: const 5 loadn 4 r1 # argument push r1 zero r1 jsr test pop r1 halt test: push rf #saves the current frame pointer #current frame pointer storer rs rf loadn 6 r2 # reserves some local space add r2 rs # gets the argument loado -2 r1 # only testing the rs push r1 pop r1 #stores contents of r1 at rf+1 storeo r1 1 #loads the same value into r3 loado 1 r3 # restores stack before return sub rs r2 storer r2 rs # restores frame before return pop rf rtn apoo-2.2/examples/test1.apoo0000640000076600000240000000024710745416725015116 0ustar rvrdialouta: const 1 b: const 2 c: const 3 m: mem 2 n: mem 1 load a R1 load b R2 load c R3 loadn m R4 storei R1 R4 inc R4 storei R2 R4 store R3 n halt apoo-2.2/examples/test1.tutor0000640000076600000240000000033410745416725015332 0ustar rvrdialout# load value 20 # constants labels # memory labels #mem [label:num[,num]*]* [label;size]* initial a:1 b:2 c:3 m;2 n;1 value 20 # exec value 30 # final R1:1 R2:2 R3:3 m:1,2 n:3 value 30 end apoo-2.2/examples/test2.apoo0000640000076600000240000000024410745416725015114 0ustar rvrdialouta: const 1 const -3 const 40 const 0 b: mem 1 loadn a R1 zero R3 ciclo: loadi R1 R2 jzero R2 fim add R2 R3 inc R1 jump ciclo fim: store R3 b halt apoo-2.2/examples/test2.tutor0000640000076600000240000000032010745416725015326 0ustar rvrdialout# load value 20 # [label:num[,num]*]* [label;size]* initial a:1,-3,40,0 b;1 value 10 # exec value 20 # final a:1,-3,40,0 b:38 R3:38 value 20 init a:9,10,10,0 exec value 10 final b:29 R3:29 value 20 end apoo-2.2/examples/teste2.apoo0000640000076600000240000000011110745416725015252 0ustar rvrdialout mem 200 loadn 50 R4 loadn 56666 R3 add R4 R3 storer R3 R5 apoo-2.2/examples/while.apoo0000640000076600000240000000021610745416725015162 0ustar rvrdialout# # while(x>o) x=x-2 #R1=x; R2=y # # suppose x=10 loadn 10 R1 loop: jneg R1 cont jzero R1 cont dec R1 dec R1 jump loop cont: halt apoo-2.2/examples/while1.apoo0000640000076600000240000000021110745416725015236 0ustar rvrdialout# # while(x>o) x=x-2 #R1=x; R2=y # # suppose x=10 loadn 10 R1 loadn -2 R2 loop: jpos R1 cont add R2 R1 jump loop cont: halt apoo-2.2/exec-apoo.master0000640000076600000240000000057110745416725014455 0ustar rvrdialout#!%python% import sys sys.path.append('/usr/lib/apoo') from vpu import * v = Vpu(32,{50000:("pass","print '%c'%(val%256),"), 50001:("val = raw_input()","print val,"), 50010:('print ','print ')}) if len(sys.argv) != 2: print "execapoo apoo_program" sys.exit(0) a = ReadProgram(sys.argv[1]) v.load(a) try: v.run() except EndOfProgram: pass apoo-2.2/html/0000750000076600000240000000000010745416720012313 5ustar rvrdialoutapoo-2.2/html/apoo.css0000640000076600000240000000177610745416725014004 0ustar rvrdialout/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */ .MATH { font-family: "Century Schoolbook", serif; } .MATH I { font-family: "Century Schoolbook", serif; font-style: italic } .BOLDMATH { font-family: "Century Schoolbook", serif; font-weight: bold } /* implement both fixed-size and relative sizes */ SMALL.XTINY { font-size : xx-small } SMALL.TINY { font-size : x-small } SMALL.SCRIPTSIZE { font-size : smaller } SMALL.FOOTNOTESIZE { font-size : small } SMALL.SMALL { } BIG.LARGE { } BIG.XLARGE { font-size : large } BIG.XXLARGE { font-size : x-large } BIG.HUGE { font-size : larger } BIG.XHUGE { font-size : xx-large } /* heading styles */ H1 { } H2 { } H3 { } H4 { } H5 { } /* mathematics styles */ DIV.displaymath { } /* math displays */ TD.eqno { } /* equation-number cells */ /* document-specific styles come next */ DIV.navigation { } DIV.small { } DIV.center { } PRE.preform { } SPAN.arabic { } SPAN.textbf { font-weight: bold } apoo-2.2/html/apoo.html0000640000076600000240000001537310745416725014156 0ustar rvrdialout Apoo An environment for a first course in assembly language programming
\begin{figure}
\epsfxsize =350pt
\epsfbox{Apoo1.ps}
\end{figure}

Apoo
An environment for a first course in assembly language programming

Rogério Reis, Nelma Moreira

DCC-FC & LIACC, Universidade do Porto

1998-2007



Comments/Suggestions



Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/help_apoo.html0000750000076600000240000000443710745416726015170 0ustar rvrdialout Apoo Workbench Interface

Apoo Workbench

The Apoo Workbench is an environment to monitoring the execution of a Virtual Processor Unit. During the execution of a program, it shows the contents of the program counter, registers and memory data. The program in memory is displayed in an Assembly language (not in a machine language). As is usual with processor units emulators, Apoo has two memory segments: the program-segment and the data-segment. In this way, both addresses for program instructions and data will begin in 0.

The Apoo Workbench allows also the editing/saving of the text program, providing an easy way to write/edit/debug/execute Apoo assembly programs.

Execution

To execute a program in the Apoo Virtual Processor Unit you must first or:

  • enter in Edit Mode and write its instructions
  • open a text file with its code

After that, you can Load it; if a "parsing error" occurs, enter edit mode and correct it; the interface will show the text line in which the error occurred.

When the program is loaded (in memory) you can execute it in three ways:

  • Run: will execute all the instructions
  • Step: will execute the next instruction and the values of the program counter, registers and memory data will be updated; the next instruction line, if exists, will have the background white
  • Continue: will execute instructions until the next breakpoint

You may set or clear a breakpoint in an instruction by double-clicking (with the mouse) on its line address number.

The button labeled Clear can be used to clear all breakpoints.

Edit Mode

In edit mode you can change the text code of a program or create a new one. To enter Edit Mode press the Edit button or New button. After editing you can Save or SaveAs the current edited text. You leave Edit Mode by loading the program (Load button) or opening a new file.

Emacs key shortcuts are provided. They can be enabled on the Preferences dialog and they get listed on the Edit menu.


© 1998-2006 Rogerio Reis, Nelma Moreira {rvr,nam}@ncc.up.pt

apoo-2.2/html/help_assembly.html0000750000076600000240000003115010745416726016041 0ustar rvrdialout Apoo assembly language

Apoo assembly language

Apoo has a set of general purpose registers (32 by default), a data memory area, a program memory area, a system stack and a program counter register.

All memory cells and registers have 32 bits.

Registers are named R0,R1,R2,R3,R4,R5,R6,R7,...

Memory Data

Memory cells are created as needed. We can reserve memory cells in two ways, using the following pseudo-instructions:

Pseudo-instructions

      Meaning
<Label:> mem n reserves n memory addresses
Label: const n1 contents of memory address
  const n2 Label is n1, of Label+1 is n2
    .... ni can be a character 'c'.
<Label:> equ n Allows a symbolic name for a number
<Label:> string "seqNWSCharacteres" Allocates memory addresses and set them to the correspondent characters ASCII codes. The characters cannot be whitespaces: use \s for space, \t for tab and \n for newline.

Label is any string beginning with a letter and containing only letters and digits with the exception of legal register names. If exists, must begin in the first column of a line

NOTE: Every memory address refered, must have been reserved by one of the previous pseudo-instructions.

E.g. the instruction load 3 R2, will cause an Out of Memory error, if at least mem 3 or three const pseudo-instructions were not given... If a equ value is used as a memory address, that address must be already reserved or be a known memory-mapped instruction. The string argument must be quoted and is converted to a sequence of ascii codes ending with 0.

System Stack

A special memory area used to implement subroutines. We can only push a value to the Stack and pop a value from it (the one in the top of the Stack). It is used by the instructions jsr and rtn. It can be manipulated by means of the push and pop instructions.

Instruction Form

<Label:> Operation <Operand1> <Operand2>

Label is any string of letters or digits; if exists, must begin in the first column of a line

Comments

A line beginning with # will be ignored by the parser; so it can be used to write comments of the program

Instruction Set

Operation Operand1 Operand2 Meanning
load Mem Ri loads contents of memory address Mem into register Ri; Mem can be a label
loadn Num Ri loads number Num into register Ri; Num can be a label
loadi Ri Rj loads contents of memory which address is the contents of Ri into Rj (indirect load)
store Ri Mem stores contents of Ri at memory address Mem; Mem can be a label
storer Ri Rj stores contents of Ri into Rj
storei Ri Rj stores contents of Ri into at memory address, which is the contents of Rj
add Ri Rj add contents of register Ri to contents of register Rj, and stores into Rj (Rj=Ri+Rj)
sub Ri Rj subtracts contents of register Rj from contents of register Rj and stores into Rj (Rj=Ri-Rj)
mul Ri Rj multiplies contents of register Ri and contents of register Rj, and stores into Rj (Rj=Ri*Rj)
div Ri Rj stores into Rj the quotient of integer division of contents register Ri by the contents of register Rj, and stores into Rj (Rj=Ri/Rj)
mod Ri Rj stores into Rj the rest of integer division of contents of register Ri by the contents of register Rj, and stores into Rj (Rj=Ri%Rj)
zero Ri   the contents of Ri becomes 0 (Ri=0)
inc Ri   increments by 1 the contents of Ri
dec Ri   decrements by 1 the contents of Ri
jump Addr   jumps to instruction address Addr; Addr can be a Label
jzero Ri Addr jumps to instruction address Addr, if contents of Ri is zero; Addr can be a Label
jnzero Ri Addr jumps to instruction address Addr, if contents of Ri is different from zero;
jpos Ri Addr jumps to instruction address Addr, if contents of Ri is positiv; Addr can be a Label
jneg Ri Addr jumps to instruction address Addr, if contents of Ri is negativ
jnzero Ri Addr jumps to instruction address Addr, if contents of Ri is different from zero; Addr can be a Label
jsr Addr   pushes the PC into the stack and jumps to instruction address Addr
rtn     pops an address from the stack into the PC
push Ri   pushes the contents of Ri into the system stack
pop Ri   pops at element from the system stack into Ri
halt     stops execution; Every program must have this instruction in order to end properly; otherwise an 'Out of Program' error will occur

Memory-Mapped Instructions

Apoo allows the configuration of a set of memory positions for special purposes. The memory values and its functionality are given as a parameter of the Apoo virtual machine. The default values allow the simulation of input/output:

Memory Position Load Store
50000 load 50000 Ri

loads 0 in Ri
store Ri 50000

writes the character which ascii code is Ri%256 in the Output Window (in graphical interface) or in stdout, in text mode.
50001 load 50001 Ri

reads an integer and stores it in Ri
store Ri 50001

writes the contents of Ri as an integer
50010 load 50010 Ri

loads 0 in Ri
store Ri 50010

writes a CR in the Output Window (in graphical interface) or in stdout, in text mode.



Here is an example:

	loadn	97	R0
store R0 50000
store R0 50010
store R0 50001
store R0 50010
load 50001 R0
loadn 5 R1
add R0 R1
store R0 50001
store R0 50010
halt

© 1998-2006 Rogerio Reis, Nelma Moreira {rvr,nam}@ncc.up.pt

apoo-2.2/html/help_tester.html0000750000076600000240000000330510745416726015531 0ustar rvrdialout Apoo Tester Interface

Apoo Tester

The Apoo Tester is an environment to monitoring the execution of a Virtual Processor Unit. During the execution of a program, it shows the contents of the program counter, registers and memory data. The program in memory is displayed in an Assembly language (not in a machine language). As is usual with processor units emulators, Apoo has two memory segments: the program-segment and the data-segment. In this way, both addresses for program instructions and data will begin in 0.

Execution

When the Tester is called with a program file it tries to load and run it. If it fails it will display the error in the message line. If a "parsing error" occurs, during "Load" the interface will show the text line in which the error occurred.

When the program is loaded (in memory) you can execute it in three ways:

  • Run: will execute all the instructions
  • Step: will execute the next instruction and the values of the program counter, registers and memory data will be updated; the next instruction line, if exists, will have the background white
  • Cont: will execute instructions until the next breakpoint

You may set or clear a breakpoint in an instruction by double-clicking (with the mouse) on its line address number.

The button labeled Clear can be used to clear all breakpoints.

Exit

The Apoo Tester will not terminate until the caller terminates.


© 1998-2002 Rogerio Reis, Nelma Moreira {rvr,nam}@ncc.up.pt

apoo-2.2/html/images.aux0000640000076600000240000000001010745416725014274 0ustar rvrdialout\relax apoo-2.2/html/images.log0000640000076600000240000001376110745416725014301 0ustar rvrdialoutThis is pdfTeXk, Version 3.141592-1.40.3 (Web2C 7.5.6) (format=latex 2007.12.31) 22 JAN 2008 13:53 entering extended mode %&-line parsing enabled. **./images.tex (./images.tex LaTeX2e <2005/12/01> Babel and hyphenation patterns for english, usenglishmax, dumylang, noh yphenation, arabic, farsi, croatian, ukrainian, russian, bulgarian, czech, slov ak, danish, dutch, finnish, basque, french, german, ngerman, ibycus, greek, mon ogreek, ancientgreek, hungarian, italian, latin, mongolian, norsk, icelandic, i nterlingua, turkish, coptic, romanian, welsh, serbian, slovenian, estonian, esp eranto, uppersorbian, indonesian, polish, portuguese, spanish, catalan, galicia n, swedish, ukenglish, pinyin, loaded. (/usr/share/texmf-texlive/tex/latex/base/article.cls Document Class: article 2005/09/16 v1.4f Standard LaTeX document class (/usr/share/texmf-texlive/tex/latex/base/size10.clo File: size10.clo 2005/09/16 v1.4f Standard LaTeX file (size option) ) \c@part=\count79 \c@section=\count80 \c@subsection=\count81 \c@subsubsection=\count82 \c@paragraph=\count83 \c@subparagraph=\count84 \c@figure=\count85 \c@table=\count86 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/usr/share/texmf-texlive/tex/latex/base/ifthen.sty Package: ifthen 2001/05/26 v1.1c Standard LaTeX ifthen package (DPC) ) (/usr/share/texmf-texlive/tex/latex/base/inputenc.sty Package: inputenc 2006/05/05 v1.1b Input encoding file \inpenc@prehook=\toks14 \inpenc@posthook=\toks15 (/usr/share/texmf-texlive/tex/latex/base/latin1.def File: latin1.def 2006/05/05 v1.1b Input encoding file )) (/usr/share/texmf-texlive/tex/latex/tools/longtable.sty Package: longtable 2004/02/01 v4.11 Multi-page Table package (DPC) \LTleft=\skip43 \LTright=\skip44 \LTpre=\skip45 \LTpost=\skip46 \LTchunksize=\count87 \LTcapwidth=\dimen103 \LT@head=\box26 \LT@firsthead=\box27 \LT@foot=\box28 \LT@lastfoot=\box29 \LT@cols=\count88 \LT@rows=\count89 \c@LT@tables=\count90 \c@LT@chunks=\count91 \LT@p@ftn=\toks16 ) (/usr/share/texmf-texlive/tex/latex/ltxmisc/a4wide.sty Package: a4wide 1994/08/30 (/usr/share/texmf-texlive/tex/latex/ntgclass/a4.sty Package: a4 2004/04/15 v1.2g A4 based page layout )) (/usr/share/texmf-texlive/tex/latex/graphics/epsfig.sty Package: epsfig 1999/02/16 v1.7a (e)psfig emulation (SPQR) (/usr/share/texmf-texlive/tex/latex/graphics/graphicx.sty Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR) (/usr/share/texmf-texlive/tex/latex/graphics/keyval.sty Package: keyval 1999/03/16 v1.13 key=value parser (DPC) \KV@toks@=\toks17 ) (/usr/share/texmf-texlive/tex/latex/graphics/graphics.sty Package: graphics 2006/02/20 v1.0o Standard LaTeX Graphics (DPC,SPQR) (/usr/share/texmf-texlive/tex/latex/graphics/trig.sty Package: trig 1999/03/16 v1.09 sin cos tan (DPC) ) (/etc/texmf/tex/latex/config/graphics.cfg File: graphics.cfg 2007/01/18 v1.5 graphics configuration of teTeX/TeXLive ) Package graphics Info: Driver file: dvips.def on input line 90. (/usr/share/texmf-texlive/tex/latex/graphics/dvips.def File: dvips.def 1999/02/16 v3.0i Driver-dependant file (DPC,SPQR) )) \Gin@req@height=\dimen104 \Gin@req@width=\dimen105 ) \epsfxsize=\dimen106 \epsfysize=\dimen107 ) (/usr/share/texmf/tex/latex/html/html.sty Package: html 1999/07/19 v1.38 hypertext commands for latex2html (nd, hws, rrm) \c@lpart=\count92 \c@lchapter=\count93 \c@chapter=\count94 \c@lsection=\count95 \c@lsubsection=\count96 \c@lsubsubsection=\count97 \c@lparagraph=\count98 \c@lsubparagraph=\count99 \c@lsubsubparagraph=\count100 \ptrfile=\write3 ) (/usr/share/texmf/tex/latex/html/htmllist.sty) (/usr/share/texmf-texlive/tex/ latex/graphics/color.sty Package: color 2005/11/14 v1.0j Standard LaTeX Color (DPC) (/etc/texmf/tex/latex/config/color.cfg File: color.cfg 2007/01/18 v1.5 color configuration of teTeX/TeXLive ) Package color Info: Driver file: dvips.def on input line 130. (/usr/share/texmf-texlive/tex/latex/graphics/dvipsnam.def File: dvipsnam.def 1999/02/16 v3.0i Driver-dependant file (DPC,SPQR) )) \sizebox=\box30 \lthtmlwrite=\write4 (./images.aux) \openout1 = `images.aux'. LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 168. LaTeX Font Info: ... okay on input line 168. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 168. LaTeX Font Info: ... okay on input line 168. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 168. LaTeX Font Info: ... okay on input line 168. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 168. LaTeX Font Info: ... okay on input line 168. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 168. LaTeX Font Info: ... okay on input line 168. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 168. LaTeX Font Info: ... okay on input line 168. latex2htmlLength hsize=349.0pt latex2htmlLength vsize=713.0pt latex2htmlLength hoffset=0.0pt latex2htmlLength voffset=0.0pt latex2htmlLength topmargin=0.0pt latex2htmlLength topskip=0.00003pt latex2htmlLength headheight=0.0pt latex2htmlLength headsep=0.0pt latex2htmlLength parskip=0.0pt plus 1.0pt latex2htmlLength oddsidemargin=18.06749pt latex2htmlLength evensidemargin=18.06749pt File: Apoo1.ps Graphic file (type eps) Overfull \hbox (1.0pt too wide) in paragraph at lines 194--196 [][] [] Underfull \hbox (badness 10000) in paragraph at lines 194--196 [] l2hSize :figure42:362.04498pt::0.0pt::349.0pt. [1 ] File: apoo_gtk_interface.eps Graphic file (type eps) Overfull \hbox (51.0pt too wide) in paragraph at lines 221--222 [][] [] l2hSize :figure215:492.59534pt::0.0pt::349.0pt. [2 ] (./images.aux) ) Here is how much of TeX's memory you used: 1283 strings out of 94075 16367 string characters out of 1165175 62548 words of memory out of 1500000 4594 multiletter control sequences out of 10000+50000 3640 words of font info for 14 fonts, out of 1200000 for 2000 645 hyphenation exceptions out of 8191 32i,5n,21p,217b,282s stack positions out of 5000i,500n,6000p,200000b,5000s Output written on images.dvi (2 pages, 648 bytes). apoo-2.2/html/images.pl0000640000076600000240000000133210745416725014122 0ustar rvrdialout# LaTeX2HTML 2002-2-1 (1.71) # Associate images original text with physical files. $key = q/{figure}htmlimage{thumbnail=0.5}{centering{{epsfxsize{=400pt{epsfbox{apoo_gtk_interface.eps}{{par{{{{par{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}\centering
\epsfxsize =400pt
\epsfbox{apoo_gtk_interface.eps}
\par\par
\end{figure}|; $key = q/{figure}{epsfxsize{=350pt{epsfbox{Apoo1.ps}{htmlimage{scale=0.5}{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}
\epsfxsize =350pt
\epsfbox{Apoo1.ps}
\end{figure}|; 1; apoo-2.2/html/images.tex0000640000076600000240000002144410745416725014315 0ustar rvrdialout\batchmode \documentclass{article} \RequirePackage{ifthen} \usepackage[latin1]{inputenc} \usepackage{longtable} \usepackage{a4wide} \usepackage{epsfig} \usepackage{html} \usepackage{htmllist} % \providecommand{\wwwrvr}{\htmlurl{http://www.ncc.up.pt/~rvr}}% \providecommand{\wwwnam}{\htmlurl{http://www.ncc.up.pt/~nam}}% \providecommand{\apooreport}{\htmlurl{http://www.ncc.up.pt/apoo/apoo-docs/apoo_report}}% \providecommand{\apooreportps}{\htmlurl{http://www.ncc.up.pt/apoo/apoo-docs/apoo_report.ps.gz}}% \providecommand{\apooreportpdf}{\htmlurl{http://www.ncc.up.pt/apoo/apoo-docs/apoo_report.pdf}} % \providecommand{\inroads}{\htmlurl{http://www.ncc.up.pt/apoo/apoo-docs/apoo_inroads.pdf}} % \providecommand{\Apoo}{\texttt{Apoo}}% \providecommand{\Apooi}{\texttt{Apoo Interface}}% \providecommand{\Apoot}{\texttt{Apoo Tutor}}% \providecommand{\Apoovm}{\texttt{Apoo32: a virtual machine for Apoo}}% \providecommand{\Apooar}{\texttt{Manipulation of activation records in Apoo}} \title{\texttt{Apoo}\\ \normalsize {An environment for a first course in assembly language programming}} \author{\htmladdnormallink{Rogrio Reis}{\htmlurl{http://www.ncc.up.pt/~rvr}}, \htmladdnormallink{Nelma Moreira}{\htmlurl{http://www.ncc.up.pt/~nam}}\\{\small DCC-FC \& LIACC, Universidade do Porto}} \date{1998-2007} \bodytext{BGCOLOR="#FFFFF0" TEXT="DARKBLUE" LINK="RED" VLINK="DARKRED" ALINK="#FF0000" ALINK="YELLOW"} \usepackage[dvips]{color} \pagecolor[gray]{.7} \usepackage[latin1]{inputenc} \makeatletter \makeatletter \count@=\the\catcode`\_ \catcode`\_=8 \newenvironment{tex2html_wrap}{}{}% \catcode`\<=12\catcode`\_=\count@ \newcommand{\providedcommand}[1]{\expandafter\providecommand\csname #1\endcsname}% \newcommand{\renewedcommand}[1]{\expandafter\providecommand\csname #1\endcsname{}% \expandafter\renewcommand\csname #1\endcsname}% \newcommand{\newedenvironment}[1]{\newenvironment{#1}{}{}\renewenvironment{#1}}% \let\newedcommand\renewedcommand \let\renewedenvironment\newedenvironment \makeatother \let\mathon=$ \let\mathoff=$ \ifx\AtBeginDocument\undefined \newcommand{\AtBeginDocument}[1]{}\fi \newbox\sizebox \setlength{\hoffset}{0pt}\setlength{\voffset}{0pt} \addtolength{\textheight}{\footskip}\setlength{\footskip}{0pt} \addtolength{\textheight}{\topmargin}\setlength{\topmargin}{0pt} \addtolength{\textheight}{\headheight}\setlength{\headheight}{0pt} \addtolength{\textheight}{\headsep}\setlength{\headsep}{0pt} \setlength{\textwidth}{349pt} \newwrite\lthtmlwrite \makeatletter \let\realnormalsize=\normalsize \global\topskip=2sp \def\preveqno{}\let\real@float=\@float \let\realend@float=\end@float \def\@float{\let\@savefreelist\@freelist\real@float} \def\liih@math{\ifmmode$\else\bad@math\fi} \def\end@float{\realend@float\global\let\@freelist\@savefreelist} \let\real@dbflt=\@dbflt \let\end@dblfloat=\end@float \let\@largefloatcheck=\relax \let\if@boxedmulticols=\iftrue \def\@dbflt{\let\@savefreelist\@freelist\real@dbflt} \def\adjustnormalsize{\def\normalsize{\mathsurround=0pt \realnormalsize \parindent=0pt\abovedisplayskip=0pt\belowdisplayskip=0pt}% \def\phantompar{\csname par\endcsname}\normalsize}% \def\lthtmltypeout#1{{\let\protect\string \immediate\write\lthtmlwrite{#1}}}% \newcommand\lthtmlhboxmathA{\adjustnormalsize\setbox\sizebox=\hbox\bgroup\kern.05em }% \newcommand\lthtmlhboxmathB{\adjustnormalsize\setbox\sizebox=\hbox to\hsize\bgroup\hfill }% \newcommand\lthtmlvboxmathA{\adjustnormalsize\setbox\sizebox=\vbox\bgroup % \let\ifinner=\iffalse \let\)\liih@math }% \newcommand\lthtmlboxmathZ{\@next\next\@currlist{}{\def\next{\voidb@x}}% \expandafter\box\next\egroup}% \newcommand\lthtmlmathtype[1]{\gdef\lthtmlmathenv{#1}}% \newcommand\lthtmllogmath{\dimen0\ht\sizebox \advance\dimen0\dp\sizebox \ifdim\dimen0>.95\vsize \lthtmltypeout{% *** image for \lthtmlmathenv\space is too tall at \the\dimen0, reducing to .95 vsize ***}% \ht\sizebox.95\vsize \dp\sizebox\z@ \fi \lthtmltypeout{l2hSize % :\lthtmlmathenv:\the\ht\sizebox::\the\dp\sizebox::\the\wd\sizebox.\preveqno}}% \newcommand\lthtmlfigureA[1]{\let\@savefreelist\@freelist \lthtmlmathtype{#1}\lthtmlvboxmathA}% \newcommand\lthtmlpictureA{\bgroup\catcode`\_=8 \lthtmlpictureB}% \newcommand\lthtmlpictureB[1]{\lthtmlmathtype{#1}\egroup \let\@savefreelist\@freelist \lthtmlhboxmathB}% \newcommand\lthtmlpictureZ[1]{\hfill\lthtmlfigureZ}% \newcommand\lthtmlfigureZ{\lthtmlboxmathZ\lthtmllogmath\copy\sizebox \global\let\@freelist\@savefreelist}% \newcommand\lthtmldisplayA{\bgroup\catcode`\_=8 \lthtmldisplayAi}% \newcommand\lthtmldisplayAi[1]{\lthtmlmathtype{#1}\egroup\lthtmlvboxmathA}% \newcommand\lthtmldisplayB[1]{\edef\preveqno{(\theequation)}% \lthtmldisplayA{#1}\let\@eqnnum\relax}% \newcommand\lthtmldisplayZ{\lthtmlboxmathZ\lthtmllogmath\lthtmlsetmath}% \newcommand\lthtmlinlinemathA{\bgroup\catcode`\_=8 \lthtmlinlinemathB} \newcommand\lthtmlinlinemathB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA \vrule height1.5ex width0pt }% \newcommand\lthtmlinlineA{\bgroup\catcode`\_=8 \lthtmlinlineB}% \newcommand\lthtmlinlineB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA}% \newcommand\lthtmlinlineZ{\egroup\expandafter\ifdim\dp\sizebox>0pt % \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetinline} \newcommand\lthtmlinlinemathZ{\egroup\expandafter\ifdim\dp\sizebox>0pt % \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetmath} \newcommand\lthtmlindisplaymathZ{\egroup % \centerinlinemath\lthtmllogmath\lthtmlsetmath} \def\lthtmlsetinline{\hbox{\vrule width.1em \vtop{\vbox{% \kern.1em\copy\sizebox}\ifdim\dp\sizebox>0pt\kern.1em\else\kern.3pt\fi \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}} \def\lthtmlsetmath{\hbox{\vrule width.1em\kern-.05em\vtop{\vbox{% \kern.1em\kern0.75 pt\hbox{\hglue.17em\copy\sizebox\hglue0.75 pt}}\kern.3pt% \ifdim\dp\sizebox>0pt\kern.1em\fi \kern0.75 pt% \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}} \def\centerinlinemath{% \dimen1=\ifdim\ht\sizebox<\dp\sizebox \dp\sizebox\else\ht\sizebox\fi \advance\dimen1by.5pt \vrule width0pt height\dimen1 depth\dimen1 \dp\sizebox=\dimen1\ht\sizebox=\dimen1\relax} \def\lthtmlcheckvsize{\ifdim\ht\sizebox<\vsize \ifdim\wd\sizebox<\hsize\expandafter\hfill\fi \expandafter\vfill \else\expandafter\vss\fi}% \providecommand{\selectlanguage}[1]{}% \makeatletter \tracingstats = 1 \providecommand{\Beta}{\textrm{B}} \providecommand{\Mu}{\textrm{M}} \providecommand{\Kappa}{\textrm{K}} \providecommand{\Rho}{\textrm{R}} \providecommand{\Epsilon}{\textrm{E}} \providecommand{\Chi}{\textrm{X}} \providecommand{\Iota}{\textrm{J}} \providecommand{\omicron}{\textrm{o}} \providecommand{\Zeta}{\textrm{Z}} \providecommand{\Eta}{\textrm{H}} \providecommand{\Nu}{\textrm{N}} \providecommand{\Omicron}{\textrm{O}} \providecommand{\Tau}{\textrm{T}} \providecommand{\Alpha}{\textrm{A}} \begin{document} \pagestyle{empty}\thispagestyle{empty}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength hsize=\the\hsize}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength vsize=\the\vsize}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength hoffset=\the\hoffset}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength voffset=\the\voffset}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength topmargin=\the\topmargin}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength topskip=\the\topskip}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength headheight=\the\headheight}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength headsep=\the\headsep}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength parskip=\the\parskip}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength oddsidemargin=\the\oddsidemargin}\lthtmltypeout{}% \makeatletter \if@twoside\lthtmltypeout{latex2htmlLength evensidemargin=\the\evensidemargin}% \else\lthtmltypeout{latex2htmlLength evensidemargin=\the\oddsidemargin}\fi% \lthtmltypeout{}% \makeatother \setcounter{page}{1} \onecolumn % !!! IMAGES START HERE !!! {\newpage\clearpage \lthtmlfigureA{figure42}% \begin{figure} \epsfxsize =350pt \epsfbox{Apoo1.ps} \htmlimage{scale=0.5} \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{subsection} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{subsubsection} \stepcounter{paragraph} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure215}% \begin{figure} \htmlimage{thumbnail=0.5} \centering \epsfxsize =400pt \epsfbox{apoo_gtk_interface.eps} \par \par \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{section} \stepcounter{section} \end{document} apoo-2.2/html/img1.png0000640000076600000240000005403110745416725013667 0ustar rvrdialoutPNG  IHDRÐ tRNSىH IDATx4鯥u޷|Ν[UU]=Il$%Kd2"Ѷ,ǎ) %ȇ$v`'ȇ@B1 DDC"5 %d7kus|iO+ gm3!냈$a?WLǢsrgxKD\ޠʏt(~poay2NZTR\꥟}ݮ^}"qSs=?:PY`AP?/}m; S/kp|;xBi'&'WR֗^_[HOy^>2ƥS rzfW ,b`p⧟'Q`ouxJs}Pi|Y~ʣ T*^G.^Jh\U{i`2Ըlw>Gq{k-QUkq AXH{1xP!KvoYI_g-1;²Nu2c(+>/HHbY}܄wA oz|hn}^RƧ_nOfjMU!/ ioQ/sY__{X{[/i00e SL@[<~Sn^_Q[N:ܬV#eGR c7n]K_S^[5̍k+,V',O"GYfwij?|s4 =[r'2 ì?l{;{So'س ?{721]HQi6 9;h~!~ޅru0NJ_f=BM`7ZJTcwf_DHmscȻw8ZziKNy3c}GJ8\ ONdpuEU8Db`E ;g+Qz_ {+~1"##8&f}K귿i14. &f@ KZRHz $B$A`Pjj bSkҺ[F2?o@QGqt|;8 jAZZ?.J@U|zԸ'մ1*fF߾+'ާ B=6һ#OO ^nt6)^턆{ޙ'9 MB9Յ~7*ߊ6*>|qdHDܝN'܌NvLUڣe?o'i]>Y-x~[">RQS7'\mm?  1(ټ;tÊ7xju׍0iI,&ʟo}hx#v/q2/,JI;Q o(- n/}Ɗ$W&x; TV3:>? 2U{rPNrg|TIPht?-<{ƍįh<a7gnBoh5]وhyfh\~u6?%: ̍0:WʇL=Kubѽb7!]^3vfՁuR/͑|U1+j2&_[=;.ީ-վZzʱdO\۝?YqRca/lqC(75?ϴ绻 L,5+{@N> we<9 ̙IqO~Xݟshxr}E`ڼoF TWDK;r~R+KiF9,Ǎ!â2^ށgAշur A&>?h$Cr1G,X/ݨkV rOVve-DTJ}mQRRopyљS=\jJΧ9t6?Hw?5XVefE҆ff>h{jJsro 3ᄆGVhS2H%#nr_^upnjB1xo2 /Wk I~9sÍŅ7)Z{mY_I{QRL餼Wٓy_ziy11qbQ3qWrw,tWG݉oĺ6i*D3d;VxϽ[no 2>&8C֕YHOU8{ B~'|4Vko<=; \^M][ -:g8 s<G]L7O/7>vm7w>4zCQi}vc?sN9H8+rfO^L͒ rq^57/^V`uS*=2ifl,,s+e4RO=OORc'tc2e<Η_~9Gis8>W73gii=-yn-hʟdΫUv̅|xcg渕/ݻ >6~PO\x鳭Vmouj52k ʜedjڇϮ\YF|Y=A?]If^O$NSOZ+ 7Ź6r ˒^.ݺ8y4HRB}VD'|} m^n]熳Zf.PS\jUPUTjpfkͭ$Q<_.ɞU4U+/޸?'[ѣ VNBNlӠk \)eK6ڤiݪ="T\V+y5Ngbl].倳ӤP zYl-THY/P*e&"g6~t1epzr\OG_oףZŕ- Ec'LOyt.=^ y5nk%~:X;V`R]007}zPml*dM&3h8 0C;Nt9/ƹi(KݰDϮGMk^B~F*Вc49*f[;9|s. Lc- YglOU+R?;y_R'S{Ϲų?i-Yh3%XN3l%=8鈊^㮟ݘ5d_ZîF㵠N_/L_|?.UiQ⧃vDu 82)P\sVO#fL'W*KWwvh7 WqeF@֎ya´wGo~+/^>}Rm D3 n>~l79F$Qq1vrfbI,V`&hD;G,,Ud|a? ,珓iy)pE0ň풁q"s¢lI"s+R^_uh ^='fIxxjSvبkZWBi04aܬR^hnb9\;8SQQoz6[Fs>x4*F>ӒY?TQTjA^ z6Y< in gX_'nΚܿ~pזitчYAlLmke^!Գ=1alo2/LLo-'k-IĔOko"ME@/h @`|s2尟 ѰloJe/~aJ Kju|P53Zzh"=';x'2_coؒE218#F@`bb4RTjG.ht4-PzXH-f*%'Se:t%0[._ &tSeܶhL(p.4X}mC@S?)zEt(@NG_X/*PfZD^U{>Y,Y\-D2:dHjGd#$@l1J4m!:%`6oz̈!3`):DpYȂ1Zx&+QBptՇ:a,p #+!0"G` $0#XB+ Τ{%"ƙb b@"8@b(AHN0%pi#& ûEdY`D0J(6:yYg1Y)!'y! ¡t"kXsDW Y)Ʊj>7Yst΢#bЭUw4ۘ Np:V.{jKih2>[s R@9" s(Y4U^yd3ywkn^hy*qEo;-h7A:lѳ7-AhQ'G{ <;=|w_>9v>]4xjfgpC$W4bj§LS;zyM|~|_\*s'+k,(}(rS&B:"dtlIOKS1iFeN]SŦz|*/BK$iP0\ҁNXG9 ^ު,Au9'uzas69Tu뉿21*YC-0VBe 3q#o> [P_4kީ;Rdihܓx9+ 4d-.:޸v'yi2whTC 8,idDp&)ړ+xa`|PIvss[{m p?_±љH."60jg%uL~JzE{I~l r)^:?:HO^LǵV8S,ȀVec `?K ba\k{poZ'ӻvcwL3&B@si sNH-oL?'YJ|4hv'zoR\oMrf'N˄HDY-5/5pK񟕊0 cfUZCQZ&A_Z,zځە2?Δp2lwkXD)0-똄63.t(Asϖ6֜|<0ĩUk`Jfs1R&+F5V;(rm=b9(3k/i^ݯ'׻(8_:ȣi ,XLLSi.uꃅϦܕt0]8WΏ϶>jz옒lT):Qp֪2Y%W0^뜇IgEyUǏONүBSݧ-.m'_t9hj! 3fk( Ul-&GkM3A|oͧN]Yn`%<5KؤP<6njѭl-;&mvGyN3-Q,ILoP)1S +4߽8-17˱i>1ďU=c/=ջο 2xL EAں0E`@*i7D;'~^Z?؊w.TN>v(86Oa$=1 e_`,@r_RRlQ8ac5NAlW]uiUImX4(1l\xp+$x@o>hƱ?/>*j*t?Y:;LWa]^5\#2rB[B0ҖBLN_2 EaNO27-n̑+:.CiKW0O=4_1^8^|0Wܨ6P@0\އ17 - ql8(p9iA4ҁ+^Ve0V)XNNzGWBWWgOqynX*t2ա KR`(D>`^(a!|4V);dzFgZm Ep|mu.kOeOUeX$]#iؔ@$?PlلR G~2}sռ^Ng+D7h>MHEa 8DR 0(&*MPY('ȓ3p~<0mr.DߎEwsA;깊kUTrYGj[sy z;Upc2e5,V;(N[-w._w,]/*-$q6〥#9 ֽ;C\e7 4Ob!sX&Ң -%΂*+AMS sxz=7X{t=rlZYí܁Uxژb/؆)%pi&̩kb]B`EnRfJ_FA5?B(̅ ʼtGNZ(9LFK_ϸҙO^=ULFSוwwlQ4czd#fOUHScZXQ*^sA &=`4z~a_5ȍϳ[kILO ]f6E4ցBZ@ >LMΦ-}uwi1V5qw'O;1ՓY(>7 f%(%BHeu4"l=Yx-Ux k߿2\{a9~qvƥ!ەk}X{\_bpgܴΰ@&NbgK|AIñ+go ,ϷW,{)2Li/#W,F q D,Ī(WTm(+Q+ӧxㅇݵb'E"wӤ:$Z:* 9c rPQQ4IYi dݸj?[tx-uo;W߿X~@erkR,sN&NAB'L/iu|Vʣg=eܧƕ݅ҕisR"+K-'VHi*P"}?W.hEv7ķt@ů@66 [*RgL`dJ tTO7_޼q{'gt"w?:<,L:Ngo'@9 }GqUf'ZNI̗?˕(2'yVh+h7Jll6if")y*(jeZ7ӧu4z跜K?g˝4Ll6&DC8 aP[X P%UOTCQy½/٫:Hr1R;Kʢ'&^k2,~ΕDCWJB 䠚WQѐ.]GoZޖ*cby|xNzґUc+c(CIcibàJdBT2Oj8i4aǶ+ܰS[ 3%23wk$g(,gD0 '#fMH2 4!(X3AY ˺GԜ_Pn9 *l'׵~͗UӋCMSk2g,7vVXY?yN^vzݡATK鸂/82%,T.JC'É7+s1q2^M|/#2S*DU2r+\qu#g~peϽJв|Vd؁ziEU g(d2.AKg"&뉸{VU4bTWm曽I\~#wOeǎ4bʑ*f9AIU ]ɠ#)[. 76QV_Cƛh%FnjYRY4?IЀ+ qڊE_DžqM 'Y u.Zq|#]͊"8Y|#,":NIf@dt0!8L,?dD_֢߹?e'5q©!H2#Ya@?U"O׆@%$'Րg_9'W߂B>212d,Ct@/<,=N|w7 Hu-231X8<@ء`K? rVqxt'3; ٠5:b&pd3"; b+,hm*i8 ˱@lk)u :|̪ ,lK'q,{oS [@`2@fr" 8a0+rу 0 0㉥d0c&'"C~\`+\9ie .M70@@hZ`1X@`l0#9ddF"'\5*Ā5め "C8FG - BDDR8 N$ k+p:! H@@,qHĀ $0 2fG=e$BϏst`HH@H`fߒ1lU2IDiB0!ʰ,,Hx,ǻ4 b,ùV9 22t&d(\Tf``4 gI;"zDlpڤjq <h LR6@dF-0"@lZ\B\H6DQX,Hf|$|y-&ARYkQ([A\yl/eE'<'V YK*?ǿ#Nj)1쬵6]Ȧ/5 7棇'aل0F%*ΐ)X!!  3q*K S9N/sŧ3xtlixz2da{d;Mxs΢(2, u-:] j@kSąE7Ae6GiI59 E٠t&d&. UaMhE59kDReeegARoL12hPvAc!yV@sΰBe0d,vd7!,,΋Jz[A22*e {iEQm9>Zi٩̨i0zr:іm =7;PDx33>ιKhYNczP*]\0zaqLK1N;wn2LQus'[- zp~%'>+ioRZ/J[YS1 Z 87ǵ$'#H Ȁ )).>߳&J: |?OPbo}ЧlG͠G&͍a0QbCQ-A-L2KrqZ]L޿|ڨv_(j-G؝iH Z'J|_% 8tV"[!; qܘo=G'GQyIzނ</db\j̥C/'~Rwx!8Շea=pzrxy q 1:V?a|+4`F`KY7$5*m08kh~٨q,XRHY4e8+mlmC"k*koI]J5cgBVn7,?I !AG="pJ6OFBe4ۡ K봘KM))t߃zZlUNW+ͺ"KĬQkt]Yz0^`iOb\B?)K ='׾-9l*˕.-,0 @0a? b1  Tb̬e|~iw콖֎n]$ъ#+ЂL B@@PI?AZ?:- 7n6sp~s׷}^WkսU\w25~7)ⷯ8ٕW$qDNgű{W)`goH" pFߝ<(t*iRۖtQ帙,w|:f.Y5m/(r¯^滟C93zT&v'cxuGLob'ނd^/ r-;{yo^u||{t"/zs:{k0^_IX,7]FOcQpD`w)b''  (>DE% x`a/~nP{x u!;hIJmPCKT.uVfޯ4mJ6?t]*c:n-[+P0,Im-)Pմʈ3 `:L823ݙT$ B|侩]N3^el?~3-տT/OzAd^,޲8\]x5Hj!*`NwncH `1"0!@f/B[=G)nal)fpܳip΋Ϻe?&hh#>yrx[i{OF? KJWU|iLc^]WJF,|p,GED(F1 P^>kNDQQOo?ZOfK.XQlP['fWpY:&b.}|i??8}fTsb{_;_H`&8e921Hj"*wpb)q+/x[!έ|/^v̚;z]I|Y-x\=Ӣ?9[?9xޟ\Cʫa}U_#%x8VZz@ WpH`5H(CL5h!?FTCw؟wӺ)TEimcCGr[ۗwP]:.>zy9hsϪk>o6ޝfEq8v? X'J"Ga L-bQ9go MGN29&*0sf3-nQ7ud?r$L>^$x,'[͡W/>{&?T 1'JDF%/4J$3U_iI"s~kVj@:-UǓ$+P70{Y=O8-Y &l~9m"_Nvl/e}6 >CbJ=aAEfUX޿_itw79d~l1lRvem01&rr,mUX^'{vG ?&޺ݿW~sofyulv4MdC QFHaSNg ʈ/xֽj3Fu&W}r}|1\9߽i>XT^f_o(7` i;fhWyD20DFGR1 347w+ Z˲Iwx7e7'8{ ]iz<><\5ͫoa~k/^5YIϑW}.!nyWHQ(8* F"0zIN@ridĻy,v_͓9m;=yGrTUGu( rCpç'֛!=[1U)Ѫl>ƈW;?xGf#(rT+yFc^޹On87p2}~ 6dfb01"u2Eq.z:LU:hN[ 3 1ZRA D/ױL1 X7:ub-@oV0V_ty姱~vw+jYׇtgfswm_`x-&NMZ?J f^cDK@%hQ@$:☷`oGwXc=sP' C=r˼A^|˳ Q/?>X}ylyQnw=3嫱;R0IE}_(&F5N `HD, *v}`\TwY_xPCvg -^|Tb7Y9ъ$`)j 4I9Q#;DEʣ`?wt1Ώָ-Gʶ}z|Tc{q5TOPsU;ՐNNiށ$ok|Y?>.oh~zճiuqEmE j A2TWvD%PX &\:{`4 e; ZqڣKM ?84|$???|iKgOZqjқBу&FMTC)P B n%'@ΘuRy)faf}m?ǜ0~t>q6ɪ2ctJw6^Ww|z߿/.`eТұ+~8) $<Ƞ NPbWy=odFT1YL'Ռ8wGЛ,#{7w*pOS]Jro=^;wXVҍE-LB@ 5$=l)TxW%Dc`C%bp,|:C 2W~E"DgU֎[o\=|=>Khhe^IԚ[j>em1cU2ZK^Mh0D21 F=:ӦqlwylmvIsIDATKs)2 ܅J6ܕs3{'11&NƗ]52l˩eF1i}[Xi1O{ءGT#<Zюd41rټ l:f`sxN#@Q0Ai{}wxߛ RFQìzdֵF';ಏU I!8hQIIkBC$i4&5 &KL,v+Sq<ʧP QgF061*ؾ=L}'nÃJlVm$ dv=8L,tdԳ2_~ȴ(}*%8rj` YPT Ӭ(oO5qsGo]Im U3D<\D#No玒;j6i!ٍXaJyL%gC"z*]g@\iR *o3ThBT_lELŬz[٩p0iچVẋ(gX%k;o8$fQ84Lf֣5g4WPV4'72sn˯*͗MQxoQ 0ݻ3V0. N> ICYo~ςajW/),m++i!&1jIӋ|Zż~Y/.6:Mגb)нf^\~u>ړp35/[\_<@bj@+n1p1ªdM\9b,c0)gc`4V4qj18Tri6ןѿg]YG~G?=>;>UL+Bs~*OsH}hi~Z ș BMN֢=p& UkPC$QJ"SrpbZܭ#&+Ƴ:ܩ۸>95׳$Uuj6YAܿSQ|alM{l$4uJ܆i1ZB(ee0naA) *غ-bs .u!}=\ 4{2G/0WYjݶ[x{Ë 66?y}Wuל :*l-d: ds >amY+LC(N%>hb[LRMO:h~[b4znGӯ/d' TYXUdﭏ\짥8\b0>lLVGRAǙɂfmMA {(Z{/@l51GJ!mKL IL'5θS=QLo-,p{Iu4'`oMuc:|yL% ٶ.Twn&?|"*!=lR5-*[5:8ClV9s/X߹yW oQU}Nc Yj'd *]j_V{*fFŬS$:V $!(Z4 g1G$-"T{XW噃nwXG{~|qwѽq}b(\I}W6bAbckG_\<_/U#;G%ӕ?4SEű%;*{0EWE$ 2Y߳ xGíùW|o7~]gQJ-v~|QN6뚓w}rqOƝM~wP 5C#V|.c4OF1EfT$QKAl2 a*M30I?ݻv>ogMby~рr{r/>Vzbk~z< 뫝;NУmp/+-Eqʳ̓ͲYU1}eԦ4od8O2JG_GM1*Q3풜:LՕ:|LqM:^{% : 5mq O>rQѱ'| CuL7J'vuzN"iA0@DEŠ-X D_4FHnIFk1 j&&B&= wu)_gF̌Ai_.XSj;(b`o D9Yctڤ\+~(AHP@|#r} $hzaU@Q 8'_}^^mݕdqP~B)3hdeQ؜ݠ1QҞm6[^hڃLV 0(䫂HHY01A]Y1jL*v@.w~u_C5m&[3fFo ٫mzޥQkeb ̤R׮$ ={/G6,Ȁ$7($D9AEE+ہ9Dz\r^{FYMO`|?7fC Z)R"D{!vVIENDB`apoo-2.2/html/img2.png0000640000076600000240000011525210745416725013673 0ustar rvrdialoutPNG  IHDR|uxgPLTEROWޓ֒pqmagoelŠ̵ _S_'(5%/v}st &#矃̦HGQdW\齾ӞߖՌӊѰˋɷÿ8(,`ZiýcV^gtRNS@f IDATx콍s$Iv7Jp} 1Ȏ2L„JziNl2Ű;0tc1ǽ%IF$YJf1;!ZL9oˬϩ@TWg/_#&i~Ym L47񂆘VCz4klf A 1UGݱ`4>3,a:]gI/y&kaْKGA MNSF`A.eIx eI*H1SÆ,+DU`v ݅ e!cbC,INa.H&Cd'H9KMӮ "CJP&h<뚠]2D5 f&lcl Xr5vhrs:$o 3lrjC.A\$!AYEl蔠UY;dFC}ih ;ҽ%W*o6JrJ!Aom%|`\&d fJ.Ax"ݭfW.ʿ0%%̦}9A/J2RZc EnpmPـU5Wp> AK0wԄ*Z7AACHPtJ0 Vaa;lۄŸej*R#i؁b %j(8X?㯘`ul EUV\qByaYTV_ԗ6%WMФ Sf;hcG,4ӅДei&U&; ('(Xd٩d$L&u[$!{9 ^TlW-A\ ë+6An"_ɱ | b0n B?Qb>u#*6gTRԿj>[TE` NP  )*5*e`PL0ICE`dؽCNC؂KB 6htIbgr&)mZ$Ȫ7[(h8$x$ 6b%pLɦίV y*uW0S fҘ _`*r5m9D+jȻ_rA6 ^_9kh[_,HZ_ ԩɵ3 en6FTm *m_NjLJ Þ"Hp_`+qIyːs=/} 2a(CGgJՁ#GKSg1x&5[4 f > xOƨpc&澱yC'Ʀ.,lr`MzZ>bz8S]I/8 ]E / W)sWz.iɴD 27}%+NS 9̧ۑLٜ^(5%iziV1NK? J1Jϋq٤%ږ.=75=bzX=Jz 57\-Y NN?N|AYz"T^fXLCU AP_)=4OzG?JmuߊQ#$6ɹ~41^Ʋx5tO[Q__:5'q>țpHi~ƪUgkPYҜPĉi/* aCJw8b]mGg$Tq=%!>6r_oPɕ<ıtm4Xu4 W;qi'~WkiNnNnդ 5UDP*?~@,Z.CgvyMajeIH_L8~yq!}/)4~&VI/M 7Vdx~=@pDMa~KM[0H˛3.a nPzck[>==s_7ob77NW*lv?o0Y0xyK 6#)OlV}Mgqz)\ЋlJ?Nu/ؼfenD?>*Yv>=YfvQI(t<7߳~xF?3d\rF#/!j)?A?*R߰~Y埨׏-я|u{ʿX)+h`Lp埊ʿ~w}oz/)_ |}jIT˿ق~#/;ˬY|ٚ~Nk7?,JB!rV?7ޛ~Q wɫ~γ~·_?_)E)[?:-~܇"{S7?zϖ/=?2J4jr rDXoe&R~0cWi]֏DmKEQvs[l/8f#R -dWן>C? :Ϊ_ 0IB_f_fEnX?5!~7R6Fe4shS~COj1UՂk`7&K,-W+V?fGw_k2?R"ȕN{♺m6FFYR U7i?~h5k g)QU?~׿P!_#H)92$m5_I"u$Ǵ\&W,_TA q7NOMk6A]4"}nmo~}f5CXI3Kgsy6Ӯ~u_=ﮫYAmW[O'>ss s]kX=}ʗע2FQ?,˿{oxO2XPTƯT~CuR֯Kfh)ߓ븴d!O.d(7ڟ[ %\'",=/li|Zw7Q~=h7/8r0֚➽]|qs_E[~BKJK/x4U2q|ЍxESiuciMxXX5qoPKN 桪+\1#3EA<>AL^/F[/77rܗr75G0h}A [A-DRAj=Q?Sf~RMYm|IR&fxSTz-ÈrV?>ɦ%WU7^77q.1Y:uxL!9D0*ASol8z%丛 ~_Z,[bj',2]Y?m0œL?-ΟO~o<>c~vG179]_RwuՆ^K%U?er6o@UAI?l7{nNmdjI~VQL?5VIG"ׯu#^0㋐)[+Ԡal0M_`.(ѧ,懢cMfh,~GI1m?59\ՇWY_%7]HᯚY̡~6#ʜ~Y>z+~ܔ~B,6e[Yj~b[_ !L㳪~>3vfܞ~vmѯo'^U/ í* kB?Wm'[OnIG)#~7{rPG{_>E+ϵOЎ&uֺy" S%r73hٱqC8Ga{ӏ;eu-ӜZF7D>`~mR_)0|]/-UU~~_S=۟_ۿ~ׂ9Vhnot ~;Gm:qBEm#۲~!p!N7֛-~̺i3x*?"<~#TN 3~i9g%-=2>&a}U 6/CVv?^gp.l.}YQ?'_9«Ӎ)z/jȌ@ȭ'2]ǃ%wY J[/u9Ǯp萻KTMLXp%U5ĶC~|.kD?WZn*~_j6ǫ/I?Z s47_(?js)Wm$n3%;/`yݡ~\ԷmWklY?;=]cWbt^]꧊O(M4Z ߔU_z np QS̍oS|KlR'%TlN?CMcWv|,2pou:*VrUWع d~?яl~.Ӑ MmgT?VҜNݯF?dS=Ws.Jܞ~a׫~Z@oSxU&QҨ.[>.ce;3M1"xC[h]c WUfUi}=ُc;&Q]ӶyT.~fi6 cV%'oY$2Ν~I(2#4n׉ލ~Tj뷃/fH?)EE85Re>yLS|k6&Qh439OyaHzϯX[~m=">WUXh9ضRxO9OS3/ DH?)Ǟ5>gsh4gTbLbU?~ŲI`rvjG'ߕF/uy*/ԅ-'L~ڱؙ~T6x]WՏ N?E!ӏOx7 -SS֏quP jS Mq1>ⴽ~԰y>~s?;߄+ètuH۹n_Uk[~AC]FFBc]j[Y?~ob;Zy_i@1J&C&|G%G[34@#/AJ—ǟ/YVW?~oBI3v \s>[aBܵ r;}y~q7gTR8RV??{X~,/7~E.~^'񌹝`8ZU<ڜfhE4ٺ\./L2qq$ϹDAv91n_b:_+__VޢF+mbb.h%ۧzU-wy[Ӊ~WJsۻPW$ǯ,c߸~z`Lw0)V.x~ m7_9 [O._{?I? mR]d%}Ͽ_c j2\|z,֯AvdW(_뷮WCΛ{ї/ _=7~Iʔ|ۺ~ rKGj^kV:ҝD>(kz%m__=b"m_~EZhDEpg*j˗:tNf]==O/o~~NG^2 6Z̿ c{ ^>m_\_K?~[T_^}ɒmzuJ>=Ki_%_ _-~K%5X= gA֭2KPFHKuEǖOvYC'>`'V_77 +eW5/6'~AnYʆ VG-FgUD |s'n6]*RshS&XZ~H8}Elq++Er lLܷwx?~w{ZskP\9cO7yH?j;y_?>>޿N)/0N=ucY'ww7☿N1n"yTyZ4~yfo!|vᑪz,\ ĸ>m粏v-hd녞k|EZM~vvv2>wG#mFh}(j,\ C!6"Bpnߢs۱H\7L]Lpn$d9°︖ַIݼT;܊7 qw-y/ IDATۀu{oT H6aE fwPw9|3mLXF|3C:tTALr/qu\rtr+vbzG^h˾p>+v ^ٗ[v2\`\Ԁ6nqq{ *Io/4wYk^%vesUsU];\X/SBk!NJ4ø(dU'6aޮ,ju9|,ռ/1wrQ6 |rw1R||Z^MT]Zŗc<ʇyKͼ z&!O$xU\q3.%slQ<utefܲJۤ$^_,Ӫ#_4 d}ա|ࣩߊLl)ikU)4L tuc_ $i-Nۅ~2[/U&irYe cb89޿:Soӣ XEKґT[>o=|tul"3'|^Gq;gw',PiAJEeݴu1 ńc#4DY{D0ÉYlD6-zV;܀/1sR oϨ6|WК<ƚ>"Y5[׵u`3-&| ǗmZ _q %|O3K >Iv갇2u0_f}S촅i~}6uYK3mٷM_;> ͨ\>båPT{{S| WǓ<2"]brNl<4i>;q5{.H?+{X!/n8!]2X1bD_J5odNXqYǏ'v\#gQT1v }*SKDwCFb!SGn-y>z1Q>to8p^u,";+;k_1{n>t>h-sqF-/ _:\} ;XT4\9 qCZʽ>uY_66kϕ|{/iJ >~ 9 HNV-t@J%Vnjvh>?^`>̾Fӆ v9Sl#,^_:d+L/n~{ Zc=I|m-ħoLX1da ƀ_6gçB;g\,7-,K*ww$^s@"6+8[sh;d4d)eT||jDi`R3ɈK[;0|)X |t*CrN,.Z zz3l}|4r:Wq>I~3OM3|H%}^="x v`u| @t ˗}Фl=Qy쭟cK\MA%"=W{ ƺIHGzDt`p&LkE^ar) L(^![VPY2t_4>Ue|~x1]l}ns\cp3bOKYd}l)>k}QԴcUj&K|'_&u$86 QP9*EG(f|>rDdƕD_åԌY|jJj9]U_碒=L0]6ޗPǴ~+|/)YU ˆ *> x /_yt _yȀqI! ?Ux_q ,}cy.z{ۑ)5}\֤7| aBʢr)'2deV(h|=|2/qPGE孏/4~}\0̔2մ/_">m6F2/ŇD-O8:zo !᫱[o[3gssqa%#4Iա8>ڭKaZnG}.wjF\j3- >ݪG2v[sj=>s|Ppi7b3HƪUn ;q+.D(7rp)|;vu^I:]Dː E>\y'<)̢V*}7Sr-8"W>yqpMxjlZӢs1tWi1;Ƭs%|T %/[xZ|4ޒfQos X J}`Q|TAi},R|t Kk > )jAA i\ ob:VKC%ziUnewN2Щ6Vىnzӗu]O6C$rD]؎ɑ,1N2y  Ox&*>GW iN@G,08:M4iQ3g|(܁tG`,1<9SN jrt褀c_Cu]D | [6"?>! /'?B::&C.ǜ!'|~ ~=EI5WD9 _l䝄,>m'GeeKwUfqi#M MV~\O⤡l2jwbl["ϯA97M"-@h6ӂ j& ?nwe~1SJ3l@r[-rϘ e^~&4[ݕFt~+>F+Qk)O` ie.\!I4Gj#J&Nh|&L34Ѐ>;0$9G |o"Ka%&|fFrwwwC7"0]kEQ I W"U_( ãRE}y?X߅ƹ4\ 2~`\JnMHڲKrI,Bi!>ƒ2.А)\ːSffIGQ9Y]BK5h:Ozpd"cEBRU} pٮSmFNNwΪU礁?֋-W+3 >

?HPp,>4Z|:G{khM{|HRz~b|>.{nF:[\=:cVHpWfWNl!㣆 2Wq_Ƿ5 >p(.c^Qoke3([ t<[K|V{V ÆKikh;jxgɹG\T=quӓO^obVxL/q.{pY]|kPv?='>']R^EUlpWy,z ]5\㆟-'|94\􍯓 w#.V>såuNh%;l@SN.y]e\n #.Ðo-%p_ꫯ*Ƕ:UT~.QM  C|PqY .U!^ʾ0E֝Ȁo-N"9.wR>3|e,>3-.EN'.:lSM zf(-.-rR|O`mOʼ+YCϣ:^+#Mˢo!$+~ ?= .E<e5.Aae}|̭]w1S\Eӵiz >|2L,6\ȼ=[ˠ*}V2utz!>e9<|#g};6{$oφ;`*ZlWN?d(b #KF!%h=@UNa jvhaVxuuaH(|j#VfJQjɀ̘ m|7';=‡4xq1v1rƓWجܯ>΄_ %V`3wģj%ZO S7]7<44;4*( JlqӟN!Ց]EIwopEׇXAn)@v,#L|4 ξհ_?J3!2)goƔ^( ڋ=|L §μs׆/H+kE%bQ%o^lC>M0nC{LZY_/"-"_8"4M܎L/Iq|;{E6ᳯ4+67[ėlsn@u9A&K~3t' X{fUrstX(4n1G#,_r6/& +\6+]| 3n2|ww|e+Y.Z||%fG:h`wۈ o$=|gvU**>lB R|3h׹"'BţJx5c弔v% Ŗ1í% `KEYy,4~.4_!,JYvzn7$xrw̒o|+62@;x/q;u͘a.7=M4ضs_"-ϜUⶐnR| 8{')7= յɍ|9v )+6“6_OdzyS|iK‡(ޟh}{`I5{89VywXiC+|NR| mInMEom%=EY/fGn3|@-mdx(U !|.V=<Ԩ+|orP9CIᾛ[0 #.L>Q8(Qʕ4 Żj'2_P#Epel64Iu@6v^5 _HȀ_4ߙd"W ַ*>ͦįqz/N/~?맳IM_,/ţg]p5oJH1w{}:X_k>Mfy XӀ/C"RVep߀[өsDe0zʈѐZPc-,U<"C{{Mva};lrȼ+|=^ǖ\B 2!>= ]kK&|!#mIy3UX1$C9W?# 疛&&,HK,B=ǧ_T嬯䜋EiTy|}?%)>,2/KO-Uocv T'|*Ru39K>O+"|ԥ9/Gwk_!6C f>T[O~ Mx~f&*OSƒ#P['BȯU_YN_dㆬ>SWKU3/s`„e^o B6>>_vw|a_~Ȁ x(zQ-l >4Ⲡ :|B=#ćw>BMmïq-XsE6,1SE|j/|Geg0%|nQֲ a3>h6lŝG&˃12 j^ Xq\.'_hWhl k >"8x|A"3R;|Mn/y ]wJͬnM[^%YO%Tr G:d.@;[z|l >և oUn}k5  _/Ư7m/l>+Y_ uQ &ߝGCe`gx%2pZ[|ysJ3'߁9+9O 1."oFטêO-ª :¤s{I*z_⠆-=3iO ֗_D>9m#|%k9`ET*Wo} }\`K|2S,Hxmt$Iyj`~m1‡MrON->uYwU"T6j9Qsk > ] 5G"Ebĭ= oOdr܂0I.]Z(^GwKxI5,;u'6% l pj}'W>r$w8?|^ 4}E腇&*r18n5&|_ySCZo`}OZMߐ59E{q(Am5/\OGXy^‡+nz `}sNyyDž[߂ hP?(Ϡ耯5Zǰ{c}O:}Jcs§[ 7npP`5E!E3RX0J ַr [cEW| l#|m/i-JDe(ka*+㫷h¯#ɍ_s5.+y(<y(jk}#lo) +d(\d>Q_iɷ^fn/u2TŮ5[}n; IDATO-eতHYCߒxw' A^>_֗6۽KOkӯ`_ܘ||Neo|}3ᬈ-h ަ8.Rab^e|?SL?fa7\$rx?Qp">.aᣊ#Wk} >5ռ-ueW·ch}ύ4}4Qaz ">g\l"pYZt;cйakrF .#| N]|cWeU #>rגK ~l7*6\a[`}ȗ@'%e_ܲ_kc F'>9;'4:8?~ y&nd| ){-֚$ِvg3rؽӦ>mEljAM:r.[aE[2Yz*-Z[¹JaIeH >vJݯk}·[x->>yY^B +5[|I=>VWu0 R|"K<$0\|m:m\sܑutS| emj^|#HqBm4ǎO6[gl&?4 /q2\[0Psvc,ώ /Ĺ J΃$5J >]3#|X>``}Me}Y6YÇjob쫆--|9*b%|Ov$x̼!p3Q4j8Rf-|Bq'Ob%|EL<^Jon͗ujvE";,+ d~߻Ð^֛ d^wXFSh(>l!'q1@&G|kԒ(VRͩv/]SCqpæ5lxDk8QE:n:K> M9Osz×*VHB͋'ƒ3[i#c},jsP{F| \^Qy֢B;Ǐ/s]^Q^{*rK}`jZX{#|b}TO^ǧquPٿk3`e ڙ8ʹf*;1ޗǗd} ߂6_"fJW8>P7×9lÅ2Z6܇ҀAk|M1>BlfunCV;tl}&bv=.pO*drLp ejb |k$B. 9Ő+;<ꀯb}l`À1u], Z mD*>v.)<>VnTVi<4*FRuW+}t yXɥV}~] " 7*},>6XJ'UG\^!>?"|/Lq~S&j __l> |7qPBj{{R~ _m#eߴl}2e֧჻vL_S_lΛzB2 #bRw5~Xڮ2&ªe_ʾG7x_ %IbGQ%GNa$yk6(m}*s}=8yYk}oQ+"S^AZB-:|/o|) y^V #;\~3_qR|{k}q+ : !ǓӋ_1WI+HK F%y1*s:hSh';v_e}׈Xt&p*/57?"|h}/8;߽F5)Ԅ W@|_/μacGpr"p;hys l0C"8tH~?LaZ| <  /WX7j ؓYS{(4Y1wa69|!lʼ*e;"c>V?< ؃uçGG!ߡf%C$}oMUWޛv_zcAZg߀oOF/᫉F #_ҋkz *T;B,>- M(*:KFB)?Ϸ ٬\&e`<2BΗX(>]M"ؑऌ&l  o* ?MdSK/o t*B?P25sJ/r8d@9BS2/໺X>n7}߀oK|tXOͿ_(L6ΰ)@aHrnE+| ~ݍ·ـW|/R|/p*-/S+&×m"Xμx'4M+QW_p(*c(ʄWcX|GkxN=8:&%Ngy Pc#.><RJ$N`QfÔ ':il9g8\.:>6=ðOE5Mb$Hb1tr?S\A'|!r |H Y$i=>2@F>Sq1VcA:xL4 1&|@dTu. /t#hyIC>o%qz9sնMZh(T639e >R|NiƗS^3v6b}ǂ/A4> ̹ᣧ#.$WiV_| |߀o7;~|<ŗwz"oy|Qxi>ts80>>?g}U_&n7b1f#._p%"O2#`Gvg|"T6W/XSȍ@Ҩvq 7u%u%3'=j~Yw1`ï1g4pi\7K#ňzK7ky!E O1pf^iǘ_rE?xH1KAI{mI11fT 3 -<=+ɋ_듡.1C=mY=CyY=m$r;[|K0ݶpy|v:iouW e ,Qłx#)>: `&cL "l >e>dB~^ D"e T"sq]F.+O_@ &ߠ(}}_OKħ? N]">BYaZ2r /`B$#&$q_'vfd-H*Uϵ" ֋$SaG87X+R\?LHL NB^d IХ61(@>[Oo P'[H.0+~|a;*=SxwR|RQ~ mz6Ʀ{6-9bkr>|uo#{8;|}}M'LJ&|~Ž7ԃaTmrf؎,r7,7c)K@||,I6%Z}mG_3>@/c]bZj[|?Ň ke|E)&UGlG:|o1 )Ouȫt1gx45\2||˳"b{Tg}oK_bol8r }2`|2q,4_*uI)p[ MK'7"}"e82{9}&_^jb p9ji}K '(װL&v<?B|_<9+W? p MoqMƝf|U#'VQv>E] 5ߜa4 2uekȼL$[|Ǵ0깍/$>OEy|:ŗ÷k-u֗bcnGRK$_ y{i2l^N?PHC!4HErAk}kK3c5зP1&Kij} Lּ‡_o3{ƫ|[<]F%K=~|6 ">}GR|־12Yzuq\<3>bORVEQtKk[|ݭXKμkؓc|;}IwS6;_M,/Y_73lEV%>kڟڃl{[ue m~| SpY߮kv2[K|k+ˀo-%d ֒q t78jl oP.')v~rk vlu#.-4Nhą{5ۮ 5Z2[K|kɀo-uao-%Gk'ϚfO[v&8J?2/;=⢺<_o#.il1`}+{[ueCMeMq۵FYm|hŀo&(>QD- w- eZr*^9Dv̘|Mʎ;m@F\ʲEʈKYݦ ֒Z2[K|kɀo-u]::]=[8g*{}t^KMF\|j>Ed2hq$q CTx=kkmʀo-9|i?E>ٍr#n)uH9*|O\Fw‡Vԡ.|_.R,|r|8Y<0G]\vc}6qHVurIwh+[ Z1#.U.Ƿ ֒5}W‡RNh}_Ჲ2[Ke]|>ዤjK7mYӮVN.Hm}We|Qag})ozghv ^?Es,\Gu̼z>]G;m-KRڍ*^˾!CӗsWwF+kuXNiU)VC§>6m:VCgٷ[|r YCA\|Ky}| /R$m{,W>5ԼpuE뀯5\Sf^ H>o >̼oJ1 JEs}l܀_ |1JV*|AK+a7Zc+(ܰ#SҰIB'1֮fxvZY +k+g ]A) -'߀o7  o~z[l}|HI K2fOB70h'gډ^U>@(46r%;%dkN >Ǧ>eEȀfD8f>_o\W?3|}ɾKMjoc먀4;ˏwY^ol<6&7-blZ_``pc>0=5wtl" sX!y!2qn#g燶^U ɀo-%d_WQu ֑ZӝP1QϟA{1 %PXh7QtAKE1#aoJ%ܵƃGL*qy ZZđH91Sha{`X_\Dž꤃Ҷzi ů}Fp$ /$Ra(-}LncU #d{)_Om`f S(Gw/@o+)oұ9>RoxV{_int:E3>iPi!@`TZpU _cl.qZh|4憬0 7ZD,_фrƇ^`V32>?nbeM%"ײd|L9;dpf|h^LA.C+g{br.㔥((錏OC32>ϜhXGQcu7[&pt44eT'#k%ʙ*v&]zfȔgv!>Yf|>ai\ϧ>@+䛩XR`( :ۮ d|Q֢)߹֣ {d|cycLY&<|l̆\`ɞ&z܄7}jH7`^b|29/?\ GՇ&3CF#&1c¨X䂉%DYȰ 8Xg:rcLj/ kMcDMKxR{6tB]\YY AP4Rp#ltK7p܎C]xGe sƗ,KN ߚ 9 &ܸٟ[8wNssƗTqGy{(l3]Jj+ j)iKo<*|s6Znzg̐\(<9iД@[[x]Yn}nr[O'Z!8Os۵/OM-…1μ`|xdak|pS3{h0;uGgzhۮ n7}f|8η9_l|/ sw6n37<n{Ǥ1S0>XP Zx29/7Ԃ 21;7#:1h| cm;7+8/gIuđi8]2k|nG L+ EA89L+OA$lb|0Ƈ%Ro9-4Ñ { 2ӛW3|rXG㛘I:1*8h|Sm-{JsGM€3pp0 /d(g8j_6\4%3h|?i0Neթ{I7#c|*ר{t4f8&4q| IDATM>n67:k@+; {pǓ#i,v/a8[1> VT-Ƨon{ %x29!3>x'q۵@ =q\>g|)J6vN76[)4Fo:RCp Kص-54iN}Qk|MPL.=Y9}mܚeַM/0y_ ص@͙|l|p=ko|v=+g|Ϧֽ}ԃZ߳3>L|=Kصm|YW7w`,=>,ut RGts^- Bnj&Qet^-W˨L:J^-Ar/01+2!vqz hƇr/~?` ]jCǥRՒ ЩBףo5O 7rcdTWSb,k|b =:|BG`|4\K%UሻAf7'S k ;==5gV?Ao0%p]2sP7_'b6`|;081o0oόpC7 v|hx&r!UyѸ}t!OU+-vmp~v} Yu8.,gxE[4[k+A| 7`|f| CkW%9'#\5@;ݚpXl|5%43<v 曱ئ_~n x V 'wQ3Po X=~@S_NMMެy"\PB6G&Mv J#` 3!90~ύ^pS`|af|i|o\fߪaq k*Ƨ2Sd|Ԟ9xg|lڞ_g/ FGEh3}P~*LpvjZ[y#90"kf}Qb ͓}˿Zuf+š⒯ޙy/WRE}f!RƷo=[~ukU6S`~pkܒ5g|h}n.T ګPncOLm[~@.~O` ~ZPF%s1LG^`|2>IʙnQV[- A%k ׯepV#q7x#vnG A/d /wvU^%x"Gv j1oYT%UIUR=NkJU,~ѷ1| _>4,>y4FԶ q#K!pW >QPk7/|I\u~mE};9|JIU=|)hHRB=ٙh3oK _|Ψ`gJ_LXu)› cRD _2| L'wKX R)M >P33ܪEi`4?RL?do"5K`Fz6J'(SO"Q6Nm_ 9-|Rd0rB/^"ǀoQ| eLOw5dLDU}K}baEK=:y|d ӡW`D)hƤG ig^`Ӫ5׾i>>r;0|3G3;KO(KJaxm%,doxͷՒy|%OSR0$7s> ~dF_ϽJS_6XwbWYu_\u2%Hç%jT^J"SzWUU +_R5fH!0`k(`fR|K|:K1|jv'_%!|3 w*wRh_deR!vDN!5ܭf&^Q~N駱2.`rxm4v]׳/e #;+bt}do%xOXAYw7,|y;Ss' (Zv] ;+Mi."mhd^# &M+(l߇JR oJ6HseH] | зjF&悋 i| .Қ<{€%.yJk{jpIXJXr;a7y*S\6ga1|M2-1_`ii^2|7;>CTZ曎_]a3{ 3O&ʠ#s "|M.A'Z%˂WJu|Eh"--~f(2~N/y3-Iei>5_bO3|ՓUKJu  _Wͷ?|-S'S3S {|:/ (Ũ>(|]c= .R?|P8‘%UxfU[*>ˤ_P[m;gsGɩ2 4cCqx:iO_`oGuZ!ޮޙaʡ]$|>5G %06"|ՖGzud9baELK(8Z |.7UgLuO1|SC?fn/1>q|w2c,L"|;U,X+軰e/Ui|T7|BW˗6+9|u4wzj>E%r>$|Ibᥤbw|&'O1Y\)GQІZj? r|eHsiÐ eèG[) ߉CR]]-5(;Jk _U+Hۀ*wc4_[{FcA4_/op|2h1| p _|IV Cť0| _/׻%i;\1||U4?_^9e/# |&cJþ]288k>o/>k>@ 0C/U-5?>d& _gͧXMGj9pd |"$oyu|*|_w"wm[>;RIxb~9:]–3{a+LqU2ϖ4/љ|u|M}Mv:JQ4o-g֕xV>g|Q2W1<D.qkɚwG;J"|0Le9 9/ӻ |RN_hh>_"c+I%%zIGTf4xf >Gt!O:&|whᓰnhE72"T|.@G5E$Ў.Ö1|v75_ Ʒ ThptokOo ><0|Sǂح]Y308c_WW/ۭ× j>E*da*xulٴP`{h>I]ޒwoBWcSv1UV]NhoR/n̨[E9j_aqa*V} ?^,TK!uE ͧ]4ˋ]^5zi>{$GJ ߔrLp᣽ȑ'h>7X §ǨL+|8b_Oͧ H3 MaebK) h[KX2! X#څ:v _O͗dbKUD>ur70|(N)' _Ɵa4C8S c XtEwg֮FjYO 8u UdDCz\[nz,hn7W x_F.Wɬ`J?e'7gzi K}&|r,:k6Źjb9LM -j_,jQ"rWW4902 /U4D2|H|cfvh>a1uK.'6[P)G3LPC۵íߝ:dpSBEڍ.6켱kN}[EIm.i]r8$E>!i>!oW -ZUjޞ]gҹ>i A,!h!8"_:CCyJOlB*GC^e*yrlRhGNgwY×A^]-QDJ>!3b/ ߨ>I |i>\!|?_7,|?3{ad,7(XSЁbw ܀%6iehwp<2WP,KkC?nvB,#$X#++Z0(˄?tOet||䎔dkF1|]n ֡<|V47r U>쟯W? P·/lZZB/OpRV a_ Ep48D)aLEͧ88'*Xu&3 ȡ|^Q(k4Tos9|4CWK"|yO)MSeC_][ e|]5A9=lg]\ֵ>;|KqC/f ʌ{HKA &sYry ŭv+g|<@7e38R3u IS|'{'#|䐃9a0ja{l· 2$y$h8\}ߑG2&Qԩ4PM5l%n]Bi&iXҧZ P=Ke_͗-lT^okkg3f7^5A_BO)*v=|vZ ~:hdL!&z>uOX _A%F O|Ffao]"K!cM֮u;@.ZC3>dk>[Sg.Vf&[OqV/!~dqjMnqc"kBǮģ'>({V.ҪŮ >X7SN/@e[$kBE"}f:kڨU ^0-sOmd5`;|O3? Ϫ zk>= a&iU&l7} {Fmu|{:H\O'Xm݆:7BWAjF1|@<_)t=O} uAoM++~*c O۶jj[~aNtoEZ:_p]K<>]s>t|oL|5ipipK'B; .2|ǃ5\hj@t5߄B78BHkgZr[R|[ 5 >t&K.”5 a[ӧ|8ڏKYtW5OskwZg7"͹1|.HDdOwϷ uʏjT+wP}V3d?%yBR墋4EZKf/MK S%`y|x|>K,qoUˌZ %sj :z[7?_Y>_TYibk&.Oe!sRUρi /$xqSƱ·i7-_aluF4 2|CuWO2jpRg3j&B_Ɍ[JzBA6X X#o |\÷CPf LȠ8eMvo]zdt>8xPULSJ?O럯XҕRd4dz+|ђ>WMɲ~5kf*/-{"rMmjhF_Y ɭA?_Gc/>Z[_sȮV-V'v ߴT;ƢCEO !w,^ R_Hϩ;䚏ZLn >THyiOQ"̅NcgҘU _dCKfRd5Z/U>Q<|2H쥪SWfeKf(yj0|u>rPR3& R,`',Ah Q_vԗ[V:q۟eptXElEho}3o 3;ֆ%HLpG >j-|Bj)GU3mmF7F()ab@$y?ۜCފg?ϑ/1_|_DgoUoU 7=#;e#|mkocQ0Xv 5KMjMkxJ!)49埏;QëQLY|9oKkW^5vC~"ݑC-z`@*|Ke BWԊNc#;3G[\a_~U:_F{/o| }oa6]Tv7nP! /ޙU>"m/C\B[S'حog/e&N?WM>E / +BZ|-"|cKj~0*wY\;ߔJaGW엶|ʦ[p7;|\g/dL|.჎g=5ߞz͗lHN~&d,FQ] q ,?Wah]q_b-[Ƃq;_j؅B1isHDݜCS|s&u0*az? bܼ:Hgpа ^|8>}e_)vyF=z\|AykvM8܀9$k=exa l܇??裏)0f|^oy6쟏*>4Y(gtZ{ >>V_Ϥ VOm6MtnjqјT;_`EfiOL! $U2|\ .ڧjɌ_`q=÷0| 1| 6t>=|n|9†1ԓw]/t aTG8sWg\boq >pOAӔ nϵG \W)Aӛ 3`Llh>!|`|!_ #|ݚO#| ^i;ko5#tk0{eZIDATiA.MS+v jT6ŝ߹ _a>cn,.&Q&Ӌyvp"%]S,U󃏜U]g'I ]Z4S_v{g C`7| W|g >Ejzy*^sPG8>IjDvV#qjE3̭~3 1sdB-U V:RXOB-=Z,dӸpK^Tk_0L|*5#-Xt5,|>>YeKj3r5)JqPL -Ak2je,.ܣ·iǫ@ADȅ Qp**igDu;g3|(;(YoӘ@yDDAVTMJ^(%k6wmlDF:CK_v ޭ sX \<` [?G> |z@o\V3: X1p_#/÷g׶&܌/c6^q inkR%ڛ/| *mN,Rܮ@ S'Đ=O<E`LeoY{Xfb >|)y:|(w]: NQ6S|ZC| _kp``F1s^/ƋW5R|'/nLyodR{ n;>]Js--kagERIU~/iw|t)[{T _xI.TG`b>c>c>c|3OwUˆ~=̍RGB49M ;CGqANے%u}5XZQlI-'%#&A5@kbGk#c] /K6 SPGMɤj!bg?{ZM>D$;JV5 |$$zLE|$:ȒYb:%@ Y?R"|1) >y*Q GzE$̪H˚wJ| >pxi5W agbO>Mf9q\ I U訿=Zx(pv?*+U>[a+Z T磘p}A:hS)"pegdRU/ >x0%9|sVEXo."Ӓ{UW51}Nr|%BOm^۸#+QMVa-)k1"Z,8; i8#a0S#h|~5 GO`Zn/o|> I~\,|\x c ̗ocxR.U1z3e \/-w; 8bCexEwx#B,z +n]/aQJ C1+u= @-|φ48-SS|>97PSUmC,[ݤQDan›W L2KՃKΐ_Kئ,Dx,_$vP<'? )/75p彗ݢS'qUZ O@sv%L6ǂV>kE83Hr|,$(v˂rY/)Gzw={gZ+_ERlкO MhxIuo2QJ|?[?|j: !:LKĵ?Ӱ/'~iZgZg/v(ߗ`9x:smcB/5=e4iw7*|Iw>2"W;>ҽeç!<>}y)}&t>[+3&|s#p; >J;>WUh>cYIg+Wj:|+0͇|;,&;Ѹ4L߼{RjQ%DJ]-wU.</'dPOO7|5x{Ȫ=V7CP鹦hI[ #|a'h蒛C?îO3:RyOHYʤV1|szw,b p,@6`T{0?M ;աOQ_wz.6W`OyVw*r3܄Sb&t?xR+}oXn:|? {kCyo6wҥп#'(Fx>)=vϠt|anWx|`%V@DU$Tz ;G8<2]GۤL/|{F'fLU= '3R?+D%j>nOm(05ǘB*Y%>y}5 ?kV#߳>3]7|CK'ttx6b%M|ЗyC'?ߙ`|ΦtOMP1M~cF>:|& ?5z,qXB/l 㙀{ꏽŮ@ jvB -_7ɯmʊ"lQO=KQt3Yo^|O˵15a\haL5*SOl.^#ZkF{ `P~{O'1o"|;"|o6{_GI<UC 瀴k}U+< {8kwL4ߨ>[WbRn1#|s+翵ƴ'09A̾zyeh]s 7dF`h̽jb/i4T14ܰ̋°bX`,sm=Epd4U &| >#//j>MX &i*HZ3$gQNY%a e73جlW9w(U?[|[;%9a+Z[qEC~WVL h`UԱRߐ/2EUMsd[VG/`>]J}j7NIiqcG=h|w;"*v> ~oO93N" ߞ. ߞ.ߙp$\cN& w2aN2]=؏ן/]o'/f4lߴͼWjoӯwNZ _M.RC}"^hhdס=/Wzҵ.vDLN5)|kN=}E yP>?N[V-Z54K";";" ߞ~oOa÷0|_S/r ÷g|paI '?#jbwL1͟Z.iղ ĭZFbW6|V-k3F /_?Çhwguod}҃jZșD|^ vUG`. ߞ.|I\KZ3GM > KPa[goi3힡0|{?| WK]= b1WK] |[Ur,ZP++40ZV-$1|WXlUK6%s%$ɤy/IzWWꟿo뫫dղcNԭZwJ]|eVVWvF%tZƔOvp5],jo+dZ_e{xM{:_J|5vj9+|Xl#>m3|7p'a: 7E tOzzNj0|" _GaQ/r~ΰ`Xx?8H|Dۅ,|)iQJE0}gN/|hia[ljя?[ g2|®24 #vH -!q3M[Ϊe{yg߭"7;c͈͒^UK{5U˰AKjeҎ:g{k>c4x"Y >BZ Y,UK G}\9[?U P;PgZ1| 毣dީ1aT#ǁo;υH $ _a0| _T%㗌5 jji C×V6|;nb`mo(īi.NjǴK]>]>!Vyx*_:T:6Ky.F8n\⃳'N>aWb+|@hd[&WquR-^5e `"ilˋ U/nb[9|4Ln >e >EMC}dv+ v(h>< r T{[0>|ֻ1vwjd4y |vag*) pܦ ڗ>uG%K}^ إUkQ[Ǭ[g _P3|7b{ _'Zo<`BM >c~W Wxr'udV>onck&9yQ4ߎ(v>;*|ӫMoQm ÷S:Ke||G>cvKͧihwӄ]ǙH}&Q_ _ OjŮL,t2hkGEWk, QvwDΗVqRAt8o!oPRKs5RiSオp|zp gɖkp+-Բ|WC[o _. []?DBd+}j0r>Qo,"+,'- r|p"Ms~"1>w] xCIl/htD͇I[|P}vnW|ĉ4>=iGjxӰٹ> h>5 1| 1|Gc.|zp(M6X}byL> r2aJp\m[Zßc,5ae^/~[[,`^5c .W.'sJƿ-0=1mJ)бpEG .HNfgk#JhV*:|P3*.wk@(okYaHׯm ҩK>]Jb_M^YYʃqSP"g槥cSJJˣ>;N}23naXN& Ʉc94wp0f؀O0A- 6,> .c085#tT%αaIENDB`apoo-2.2/html/internals.pl0000640000076600000240000000163310745416725014660 0ustar rvrdialout# LaTeX2HTML 2002-2-1 (1.71) # Associate internals original text with physical files. $key = q/sec:files/; $ref_files{$key} = "$dir".q|node10.html|; $noresave{$key} = "$nosave"; $key = q/sec:apoointerface/; $ref_files{$key} = "$dir".q|node6.html|; $noresave{$key} = "$nosave"; $key = q/sec:apootutor/; $ref_files{$key} = "$dir".q|node7.html|; $noresave{$key} = "$nosave"; $key = q/apooar/; $ref_files{$key} = "$dir".q|node5.html|; $noresave{$key} = "$nosave"; $key = q/aw/; $ref_files{$key} = "$dir".q|node6.html|; $noresave{$key} = "$nosave"; $key = q/at/; $ref_files{$key} = "$dir".q|node6.html|; $noresave{$key} = "$nosave"; $key = q/sec:vpu/; $ref_files{$key} = "$dir".q|node4.html|; $noresave{$key} = "$nosave"; $key = q/sec:apoovm/; $ref_files{$key} = "$dir".q|node8.html|; $noresave{$key} = "$nosave"; $key = q/download/; $ref_files{$key} = "$dir".q|node9.html|; $noresave{$key} = "$nosave"; 1; apoo-2.2/html/labels.pl0000640000076600000240000000340710745416725014124 0ustar rvrdialout# LaTeX2HTML 2002-2-1 (1.71) # Associate labels original text with physical files. $key = q/sec:files/; $external_labels{$key} = "$URL/" . q|node10.html|; $noresave{$key} = "$nosave"; $key = q/sec:apoointerface/; $external_labels{$key} = "$URL/" . q|node6.html|; $noresave{$key} = "$nosave"; $key = q/sec:apootutor/; $external_labels{$key} = "$URL/" . q|node7.html|; $noresave{$key} = "$nosave"; $key = q/apooar/; $external_labels{$key} = "$URL/" . q|node5.html|; $noresave{$key} = "$nosave"; $key = q/aw/; $external_labels{$key} = "$URL/" . q|node6.html|; $noresave{$key} = "$nosave"; $key = q/at/; $external_labels{$key} = "$URL/" . q|node6.html|; $noresave{$key} = "$nosave"; $key = q/sec:vpu/; $external_labels{$key} = "$URL/" . q|node4.html|; $noresave{$key} = "$nosave"; $key = q/sec:apoovm/; $external_labels{$key} = "$URL/" . q|node8.html|; $noresave{$key} = "$nosave"; $key = q/download/; $external_labels{$key} = "$URL/" . q|node9.html|; $noresave{$key} = "$nosave"; 1; # LaTeX2HTML 2002-2-1 (1.71) # labels from external_latex_labels array. $key = q/sec:apoointerface/; $external_latex_labels{$key} = q|3.3|; $noresave{$key} = "$nosave"; $key = q/sec:apootutor/; $external_latex_labels{$key} = q|3.4|; $noresave{$key} = "$nosave"; $key = q/apooar/; $external_latex_labels{$key} = q|3.2|; $noresave{$key} = "$nosave"; $key = q/aw/; $external_latex_labels{$key} = q|3.3|; $noresave{$key} = "$nosave"; $key = q/sec:vpu/; $external_latex_labels{$key} = q|3.1|; $noresave{$key} = "$nosave"; $key = q/at/; $external_latex_labels{$key} = q|3.3|; $noresave{$key} = "$nosave"; $key = q/sec:apoovm/; $external_latex_labels{$key} = q|3.5|; $noresave{$key} = "$nosave"; $key = q/download/; $external_latex_labels{$key} = q|4|; $noresave{$key} = "$nosave"; 1; apoo-2.2/html/node1.html0000640000076600000240000001076710745416725014230 0ustar rvrdialout What's new

What's new

2007-12-24
Apoo Interfacenew version 2.1.0. This is a contribution by Ricardo Cruz. Major changes:
  • Two mirror views of the memory data: static data and system stack
  • Visualization of the current activation record, with the frame and stack pointers
  • Allows multiple tabs in the same window

2006-11-24
Apoo 3.0 version has new instructions for activation records 3.2.
2006-10-30
Apoo 2.0 out. New Apoo interface based on pygtk: GTK+ for Python. This is a contribution by Ricardo Cruz
2006-04-15
Two new pseudo-instructions were added: equ and string. Now, a const value can also be a character 'c' (interpreted as its ascii code). A new instruction was added: jnzero, with the obvious semantics.

2006-04-15
A machine code for the Apoo assembly was designed and an assembler provided in Haskell. This is a contribution by Pedro Vasconcelos
2004-11-02
Apoo version 1.3 has a memory-mapped feature that allows in particular input/output.
2003-11-28
Apoo was reported in the Daily Python- URL
2003-11-15
A executable version for Windows was released.

Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node10.html0000640000076600000240000002432310745416725014301 0ustar rvrdialout Files Subsections


Files

Here is a brief description of the Apoo package. Files location can change with different distributions...

Execution files

File   Location (deb)   Description    
apoo   /usr/bin/apoo   Without options launches the Apoo Worbench (optionally with a filename); with -t (or ) runs Apoo Tester (a filename is mandatory); with -h (or ) displays usage    
  /usr/bin/apoo-tutor   Apoo Tutor. Usage:    

Module files

File   Location (deb)   Description    
vpu.py   /usr/lib/apoo/vpu.py   Apoo Virtual machine    
vpu_tutor.py   /usr/lib/apoo/vpu_tutor.py   Apoo Tutor    
interface.py   /usr/lib/apoo/interface.py   Apoo Interface    
constants.py   /usr/lib/apoo/constants.py   General stuff...    

Help files

Until 1.4 version the help files were:
File   Location (deb)   Description          
help_apoo.txt   /usr/share/doc/apoo/help_apoo.txt   ApooWorkbench description          
help_tester.txt   /usr/share/doc/apoo/help_tester.txt   Apoo Tester description          
help_ass.txt   /usr/share/doc/apoo/help_ass.txt   Assembly Language          
examples   /usr/share/doc/apoo/examples   Some Apoo programs          

For newer versions the help files are:
File   Location (deb)   Description          
interface.{txt,html}   /usr/share/doc/apoo/interface.html   ApooWorkbench description          
tester{txt,html}   /usr/share/doc/apoo/tester.html   Apoo Tester description          
language{txt,html}   /usr/share/doc/apoo/language.html   Assembly Language          
examples   /usr/share/doc/apoo/examples   Some Apoo programs          

Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node11.html0000640000076600000240000000551310745416725014302 0ustar rvrdialout Documentation

Documentation

A detailed description of the system can be found in the following publications:



Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node12.html0000640000076600000240000000504410745416725014302 0ustar rvrdialout Contributors

Contributors

Thanks are due:

  • students of the Computer Science Department, Faculty of Science, University of Porto.
  • colleges that teached Apoo as a first assembly language, namelly José Paulo Leal, Sabine Broda, Luís Damas, Álvaro Figueira, Luís Antunes and Ricardo Lopes.
  • Luís Damas for an executable version of Apoo 1.0 for Windows
  • Mário Florido for using Apoo as target assembly language in a Compilers course; suggestions for providing input/ouput and activation records.
  • Pedro Vasconcelos for the Apoo32 virtual machine; some new pseudo-instructions and vpu instructions.
  • Ricardo Cruz for the Apoo Interface based on pygtk



Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node2.html0000640000076600000240000000644610745416725014230 0ustar rvrdialout About Apoo

About Apoo

Apoo is an environment for programming in a simple assembly language. It is implemented in Python and has the following components:

*
the Apoo vir tual machine is a virtual processor with a very simple architecture and instruction set that mimics almost all the essential features of a modern microprocessor. As the aim is to teach assembly language, there is no machine code associated with the instruction set.
*
the Apoo Interface is a graphical environment that monitors the state of the machine during the execution of a program and allows the writing/editing/execution of programs in assembly language.
*
the Apoo Tutor is a module that aims the grading of student programs based on a description of what should be the execution of the program for specified input data sets.

A machine code translation and an assembler implemented in Haskell are also available.


Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node3.html0000640000076600000240000000726210745416725014226 0ustar rvrdialout How to use

How to use



Subsections

Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node4.html0000640000076600000240000004232210745416726014224 0ustar rvrdialout Apoo assembly language Subsections


Apoo assembly language

Apoo has a set of general purpose registers (32 by default), a data memory area, a program memory area, a system stack and a program counter register.

All memory cells and registers have 32 bits.

Registers are named R0,R1,R2,R3,R4,R5,R6,R7,...

Memory Management

The size of the RAM is predefined (e.g. 1K) and divided into two areas: static memory and system stack. The static memory, begins at address 0 and it is allocated when a Apoo program is loaded. Static memory cells can be reserved in in two ways, using the following pseudo-instructions:

Pseudo-instructions

      Meaning
<Label:> mem n reserves n memory addresses
Label: const n1  
  const n2 contents of memory address Label is n1, of Label+1 is n2
    .... ni can be a character 'c'.
<Label:> equ n Allows a symbolic name for a number
<Label:> string "seqNWSCharacteres" Allocates memory addresses and set them to the correspondent characters ASCII codes. The characters cannot be whitespaces: use for space, for tab and for newline.

Label is any string beginning with a letter and containing only letters and digits with the exception of legal register names. If exists, must begin in the first column of a line

NOTE: Every memory address refered, must have been reserved by one of the previous pseudo-instructions.

E.g. the instruction load 3 R2, will cause an Out of Memory error, if at least mem 3 or three const pseudo-instructions were not given... If a equ value is used as a memory address, that address must be already reserved or be a known memory-mapped instruction. The string argument must be quoted and is converted to a sequence of ascii codes ending with 0.

System Stack

The system stack occupies the rest of the RAM (growing for higher addresses). Since Apooversion 3.0 it can be used in an advanced way to implement activation records (see section 3.2).

However in can be used in a simpler way to implement subroutines. We can only push a value to the Stack and pop a value from it (the one in the top of the Stack). It is used by the instructions jsr and rtn.

It can be manipulated by means of the push and pop instructions.

Instruction form

<Label:> Operation <Operand1> <Operand2>

Label is any string of letters or digits; if exists, must begin in the first column of a line

Comments

A line beginning with # will be ignored by the parser; so it can be used to write comments of the program

Basic Instruction Set

Operation Operand1 Operand2 Meanning
load Mem Ri loads contents of memory address Mem into register Ri; Mem can be a label
loadn Num Ri loads number Num into register Ri; Num can be a label
loadi Ri Rj loads contents of memory which address is the contents of Ri into Rj (indirect load)
store Ri Mem stores contents of Ri at memory address Mem; Mem can be a label
storer Ri Rj stores contents of Ri into Rj
storei Ri Rj stores contents of Ri into at memory address, which is the contents of Rj
add Ri Rj add contents of register Ri to contents of register Rj, and stores into Rj (Rj=Ri+Rj)
sub Ri Rj subtracts contents of register Rj from contents of register Rj and stores into Rj (Rj=Ri-Rj)
mul Ri Rj multiplies contents of register Ri and contents of register Rj, and stores into Rj (Rj=Ri*Rj)
div Ri Rj stores into Rj the quotient of integer division of contents register Ri by the contents of register Rj, and stores into Rj (Rj=Ri/Rj)
mod Ri Rj stores into Rj the rest of integer division of contents of register Ri by the contents of register Rj, and stores into Rj (Rj=Ri%Rj)
zero Ri   the contents of Ri becomes 0 (Ri=0)
inc Ri   increments by 1 the contents of Ri
dec Ri   decrements by 1 the contents of Ri
jump Addr   jumps to instruction address Addr; Addr can be a Label
jzero Ri Addr jumps to instruction address Addr, if contents of Ri is zero; Addr can be a Label
jpos Ri Addr jumps to instruction address Addr, if contents of Ri is positiv; Addr can be a Label
jneg Ri Addr jumps to instruction address Addr, if contents of Ri is negativ
jnzero Ri Addr jumps to instruction address Addr, if contents of Ri is different from zero; Addr can be a Label
jsr Addr   pushes the PC into the stack and jumps to instruction address Addr
rtn     pops an address from the stack into the PC
push Ri   pushes the contents of Ri into the system stack
pop Ri   pops at element from the system stack into Ri
halt     stops execution; Every program must have this instruction in order to end properly; otherwise an 'Out of Program' error will occur

Memory- mapped instructions

Apoo allows the configuration of a set of memory positions for special purposes. The memory values and its functionality are given as a parameter of the Apoo virtual machine. The default values allow the simulation of input/output:


Memory Position Load Store
50000
load 50000 Ri
loads 0 in Ri
store Ri 50000
writes the character which ascii code is Ri%256 in the Output Window (in graphical interface) or in stdout, in text mode.
50001
load 50001 Ri
reads an integer and stores it in Ri
store Ri 50001
writes the contents of Ri as an integer
50010
load 50010 Ri
loads 0 in Ri
store Ri 50010
writes a CR in the Output Window (in graphical interface) or in stdout, in text mode.


Here is an example:

	loadn	97	R0
	store	R0	50000
	store 	R0	50010
	store	R0	50001
	store	R0	50010
	load	50001	R0
	loadn	5	R1
	add	R0	R1
	store	R0	50001
	store 	R0	50010
	halt

Examples

Some Apoo programs can be found here

Memory- mapped instructions

Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node5.html0000640000076600000240000001216410745416726014226 0ustar rvrdialout Manipulation of activation records in Apoo


Manipulation of activation records in Apoo

This is an extension of the Apoo vpu for dealing with activation records. It is available as version 3.0.

There are two programmable registers to address the system stack: stack register and frame register. They correspond to the last two registers of a Apoo vpu configuration, Rn-1 and Rn-2, but are aliased to rs and rf, respectively. The stack register rs contains the address of the last stack memory cell (or -1 if no static memory is allocated). The instructions jsr, rtn, push and pop manipulates the stack in the usual way. Besides that, the contents of the stack register can be manipulated as any other register.

The frame register can be used for the implementation of local information (on the system stack). It contents should be the first stack address of the current activation record. Like the stack register it can be manipulated as any other register, but it is also used in two special instructions: storeo and loado.

storeo Ri Num
stores the contents of register Ri at memory address (rf) + Num, where Num is an integer.

loadeo Num Ri
loads the contents of memory address (rf) + Num into register Ri, where Num is an integer.

In both instructions, if Num is non negative it should correspond to local memory and if it is negative, possibly corresponds to arguments of a subroutine call.

Here is an example of the use of these registers, for the implementation of subroutines with arguments (passed on the stack) and local memory.

n:	const 5
	loadn 4 r1
      # an argument
	push r1
	zero r1
	jsr test
	pop r1
	halt
test:	push rf 
	#saves the current frame pointer
	#current frame pointer
	storer rs rf 
	loadn  6 r2
	# reserves some local space
	add    r2 rs 
	# gets the argument  
        loado -2 r1 
      # only testing the rs
	push r1    
	pop r1
	#stores contents of r1 at rf+1
	storeo r1 1
	#loads the same value into r3
	loado 1 r3  
	# restores stack before return 
	sub rs r2   
	storer r2 rs
	# restores frame before return
	pop rf      
	rtn

A more complete example can be found here.

Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node6.html0000640000076600000240000001773310745416726014236 0ustar rvrdialout Apoo Interface Subsections


Apoo Interface

This module is launched by the apoo command.

The Apoo Interface is an environment to monitoring the execution of a Virtual Processor Unit.

Figure 1: Apoo Interface
\begin{figure}\centering
\epsfxsize =400pt
\epsfbox{apoo_gtk_interface.eps}
\par\par
\end{figure}

During the execution of a program, it shows the contents of the program counter, register, memory data and output window. The program in memory is displayed in an Assembly language (not in a machine language). As is usual with processor units emulators, Apoo has two memory segments: the program-segment and the data-segment. In this way, both addresses for program instructions and data will begin in 0.

It has two modes:

The Apoo Workbench
allows also the editing/saving of the text program, providing an easy way to write/edit/debug/execute Apoo assembly programs. It is launched when apoo is called without options (optionally with a filename).
The Apoo Tester
allows only to execute a program. It is launched with option -t (or -tester), and a filename is mandatory. This module is can be used during examinations.

How to execute a program

To execute a program in the Apoo Virtual Processor Unit you must first or:

  • enter in Edit Mode and write its instructions
  • open a text file with its code

After that, you can Load it; if a "parsing error" occurs, enter edit mode and correct it; the interface will show the text line in which the error occurred.

When the program is loaded (in memory) you can execute it in three ways:

Run
will execute all the instructions
Step
will execute the next instruction and the values of the program counter, registers and memory data will be updated; the next instruction line, if exists, will have the background white
Continue
will execute instructions until the next breakpoint

In an instruction line, you can set/clear a breakpoint:

to set a breakpoint:
Press <Double>-Button1 in that line

to clear breakpoint:
Press <Double>-Button1 (or <Double>-Button2)

The button labelled Clear can be used to clear all breakpoints

Edit Mode

In edit mode you can change the text code of a program or create a new one. To enter Edit Mode press the Edit button or New button. After editing you can Save or SaveAs the current edited text. You leave Edit Mode by loading the program (Load button) or opening a new file.

The following Emacs-like commands are implemented:

<Control-k> kill-line
<Control-y> yank
<Control-w> kill-region
<Escape>w(or <Alt-Space>) copy-region-as-kill
<Control-at>(or <Control-Space>) set-mark-command
<Control-a> beginning-of-line
<Control-e> end-of-line
<Control-Home> beginning-of-buffer
<Control-End> end-of-buffer
<Control-d> deletes the character to the right of the insertion cursor.

Implementation

Until version 1.4, apoo interface was based in TkInter. Newer versions are based in pygtk, and are being developed by Ricardo Cruz. For the new versions we also thanks the comments of several students from DCC, specially Norberto Lopes and Hugo Serrano.

Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node7.html0000640000076600000240000000500510745416726014224 0ustar rvrdialout Apoo Tutor


Apoo Tutor

Given an Apoo program and a script, this module valuates the program by ``executing'' the script.

This module can be executed, from an UNIX shell (or by other program) with the following arguments:

$ apoo-tutor <tutor-script> <apoo-program>

See the documentation for details of the format of the tutor scripts.

Some examples of pairs tutor-program can be found here.



Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node8.html0000640000076600000240000000453210745416726014231 0ustar rvrdialout Apoo32: a virtual machine for Apoo


Apoo32: a virtual machine for Apoo

This is a proposal for a machine code translation for Apoo Assembly. An assembler prototype in Haskell was written by Pedro Vasconcelos.



Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/node9.html0000640000076600000240000000637310745416726014237 0ustar rvrdialout Download


Download

The Apoo system requires Python (>= 2.1).

Until version 1.4 Apoo interface required Tkinter.

From that version on it requires pygtk: GTK+ for Python, and also (gtk, pango, gobject).

It was mainly maintained for GNU Linux Systems.

It is available as package for Debian in its standard distribution. Packages and sources are available here. And if you really want an executable for Windows can be found here.



Subsections

Rogrio Reis,Nelma Moreira 2008-01-22
apoo-2.2/html/pub.css0000640000076600000240000000135610745416726013627 0ustar rvrdialout/* implement both fixed-size and relative sizes */ SMALL.XTINY { font-size : xx-small } SMALL.TINY { font-size : x-small } SMALL.SCRIPTSIZE { font-size : smaller } SMALL.FOOTNOTESIZE { font-size : small } SMALL.SMALL { } BIG.LARGE { } BIG.XLARGE { font-size : large } BIG.XXLARGE { font-size : x-large } BIG.HUGE { font-size : larger } BIG.XHUGE { font-size : xx-large } BODY { background-color:"#FFFFF0"; color: DARKBLUE; } /*h1,h2,h3 { color: LightBlue; }*/ h1,h2,h3 { color: #005A9C;} a { color: red; } a.offsite { font-style: oblique; } a:visited { color: darkred; } a:hover, a:active, a:focus { background: #FFFFAA; } blockquote { font-size: small} dt { font-weight: bold } th { }apoo-2.2/html/Timg2.png0000640000076600000240000001636310745416726014023 0ustar rvrdialoutPNG  IHDRBPLTE0//stt__ΎEFF°Ƕ׋YYYWWWOOO!!CCC򓑎###VVU ͪw׏Ռӊ|||ábbbȲtff桢豽""" IDATx]Qk&k4I|wH cqn1 {Uw;8ēnI-5#k~T]]fKB FPe #>%XTJ |ypJY̴^.ǔ2I:]II-hIy(Ņ։:֙f&o[t |):7)!0˘-FoH.kL: Vq$R*J cOiО@{DY4āH u9y$_4&Nt@FzO2)ϨffAB $(z~R鏂68@2tV3Q35,/yVaBG#Vsd?-i_8ܷkkid5Ȼw^C)7$^\&ݤ3Wy ~/ H 2 -knZPicb ]u^ qGԳ \Z C!@;>|ӂɘSD{7I$fJg̽j]T^@YۭͥȖ ͤ{~>F U"Ǐ~[&z?F~{ܤ|mEMAƺcXF_y w`;WJ 7GZD dw^-ncRۀhκ> O'4>y'OtyE :3AB߄!l)n61Z j :'wQ .z(2@0Tgܫ3oF*jwlq;Dг4I|ZLìUZ$, i IPv/@<=MRзmbDjn@|Yk'>zF`x!=S jlfmr6|dL.d5jپ䶜r$qp !&5`2KyGΗI bV)nuv]HK,L[x|;Hrnլ,r$(ܮbg. E'E^j#TO+ # V= c3CPWXxGT6+߱Aؾ>ҧx0՛sK&^_tqDmpSǻx%-'eo/i0)l #>^0A)uYݛ!1*挚Iw]kN{~-g՛r8*v5=M8^0'=/3z.eCŽ;$Zé r累Ӿu _ql„CMLO,?@^Tl5W }eZvxRO4< 'oø vS12 s ˜@;HWT$FU9l3= j8 ny_XY&$V92N OL+Q{w |T;܉|ׯJ-b助b;?z bX ɽLscre'&zdk MЌmmuJFA`&x59/>HJ.71y᳟'t/T0<7ޕ 'mLրK:IA֌< 7+"@\V/4 H"G}A*r AstqlWi0]A&[9# }@oRô]7dUKہT  3vg3{qrkrw[@*s̵7lk*nWLeWVLn(EA^a0vug9֌O ՘@"7ȺIx@ت bB&|]s<(҆48f5F^|k{4ʤcPlS>:@/WÀl-%ytH:Rt7:|3xѷWϾ=? d]LZcWw;gjxI9}q^/2 ,vıдW aGd#'¸!HxŮ0& & /8dm< ^qhT}"adPrE[$-"E9Ks^׉S j ɘo񆣨ZIj}bSq1ӕ 6v$jM|{O=`ԉ$=qS"xs^#n{'s"ꁟD܎DxjqȪ65Sss)%@WZ"'HaxYX4},йyG~VA%cDwA=f]QO2k|Z< {|dȾ\x櫲t&)_ w2sJq&ﻈP),2 prPE=d7# )4k"tv7辧EhW"n,lf"뗒5UԘjYU܃G3ɠBwHD`w&q^Zw$"$o*3GXh~w!g+}ivMD8^4)^7,R.sD<RfHK$13rvu* qF{E~rI(&zI\r"b%Ϣw"1L$4,QlAs` һADR@."M~F#GډO73 ~JDWىkqG$G̀xDkz d"D"S<h[P_M=m#bI#9*3|JϪfE(qhgdžW&c=ޘZ^tcDo$!."# NHR'RB/p_Sk>&qȾh'2HcyAD{̾~ lx ^Tc/(8Hz$"]}-ʹ=9&v"-/=]- MśG#E4\@/Jz?N$&GgK/UO"9% "K&"D;&`9{\8"VgXDw.Hk@,xvAĴ_7ȅE"Fi_2xH_7M΁F ;G%"`ADb9R-kr"DjVH "EDBnڊ|'ۙ9P9qW+:7I(v,$QY昶p?DbFsM&ZP~7Dۑwg"4Q8 xh̦t>?ل嘈p0\_j$pяb!l" ik_U KU聚,]Um"IA f"x_TKldEE`HC#:4JW WD#t]I)Cj]wD:W-M$:M8|g b>NȶDg/{j~ #lMd \7TDh%ky4^"z̾#sEd/"+D>%b9V"x5ٹ~ ZS"{$&`޷Smw@d巬dODڤ}Ho"!%l"Gm~ =4y.U_xt"A5"V#7j}JdcbEnIx 8Xfcπ.OEZ&i+BD.QK('fa7?ߒJt, k?%AD/%*"aLd1,̉ ࣢-aȺ9+Zml!\)i)-N$\GߝHG:H#k-ڋEanHlV̪.W"[Ŭ[M{DPj_/lFϛ/ "QFxnw9^xnD}XޅЖޗ1ɟWzO+23IENDB`apoo-2.2/html/WARNINGS0000640000076600000240000000021110745416726013467 0ustar rvrdialoutNo implementation found for style `a4wide' counter subsubsection not defined couldn't convert character inodot into available encodings apoo-2.2/interface.py0000640000076600000240000026373610745416725013710 0ustar rvrdialout#!/usr/bin/python # -*- coding: utf-8 -*- """ interface.py - a GTK+ frontend for the Apoo processor Copyright (C) 2006, 2007 Ricardo Cruz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ import os, sys import ConfigParser import gtk, pango, gobject from vpu import * from constants import * VERSION = "2.1.0" # Definitions (non-configurable) APOO_CONFIG_FILE = os.path.join (os.environ.get("HOME"), ".apoo") DOCS_PATH = "/usr/share/doc/apoo/" if not os.path.exists (DOCS_PATH): dirname = os.path.dirname (sys.argv[0]) if len (dirname): DOCS_PATH = dirname + "/docs/" else: DOCS_PATH = "docs/" DOC_APOO = "help_apoo" DOC_TESTER = "help_tester" DOC_ASSEMBLY = "help_assembly" # Configurable (via arguments): test_mode = False # --tester # Configurable (via the preferences dialog): # (up-case are variables we don't touch, so we know the defaults.) REGISTERS_NB = registers_nb = 8 RAM_SIZE = ram_size = 1000 MAX_STEPS = max_steps = 1000 # to cut on infinite loops INPUT_OUTPUT = input_output = 50001 # magic numbers OUTPUT_ASCII = output_ascii = 50000 OUTPUT_CR = output_cr = 50010 SHORTCUTS_STYLE = shortcuts_style = "desktop" # "desktop" or "emacs" default_dir = None MIRROR_MEMORY = mirror_memory = "no" # "hor", "ver" or "no" # Utilities def digits_on (nb): # returns the digits of a number (eg. 250 => 3) if nb < 10: return 1 return digits_on (nb / 10) + 1 def is_blank (ch): # helpers return ch == ' ' or ch == '\t' or ch == '\n' or ch == '\0' def reverse_lookup (dict, value): for i in dict.keys(): if dict[i] == value: return i return None # We need to explicitely specify font size, so let's get what # was the font size (which would be the default) def set_monospace_font (widget): font_desc = widget.get_pango_context().get_font_description() font_desc.set_family ("monospace") widget.modify_font (font_desc) # By specifying a tone (from 0 to 255) and a style, it calculates a # proper color. def get_tone_color (style, tone): # we find the highest color component, and calculate the ratios accordingly # so, eg: (84, 151, 213) -> (0.39, 0.71, 1.00) syscolor = style.bg [gtk.STATE_SELECTED] max_color = max (max (syscolor.red, syscolor.green), syscolor.blue) red_ratio = (syscolor.red * 1.0) / max_color green_ratio = (syscolor.green * 1.0) / max_color blue_ratio = (syscolor.blue * 1.0) / max_color red = int (red_ratio * tone) green = int (green_ratio * tone) blue = int (blue_ratio * tone) return get_color (red, green, blue) def get_color (red, green, blue): return gtk.gdk.Color (red << 8, green << 8, blue << 8, 0) ## Our own widgets # Extends GtkTextBuffer to add some basic functionality: # * undo/redo, * file reading/writting class TextBufferExt (gtk.TextBuffer): def __init__ (self): gtk.TextBuffer.__init__(self) # actions stacks, so we can undo/redo self.undo_reset() self.ignore_event = False # public: def undo_reset (self): self.do_stack = [] # of type [ ('i', 30, "text"), ('d', 20, "other") ] self.do_stack_ptr = 0 def can_undo (self): return self.do_stack_ptr > 0 def can_redo (self): return self.do_stack_ptr < len (self.do_stack) def undo (self): if self.can_undo(): self.do_stack_ptr -= 1 action = self.do_stack [self.do_stack_ptr] self.do (action, True) def redo (self): if self.can_redo(): action = self.do_stack [self.do_stack_ptr] self.do_stack_ptr += 1 self.do (action, False) def read (self, filename): try: file = open (filename, 'r') self.set_text (file.read()) file.close() except IOError: return False self.undo_reset() self.set_modified (False) return True def write (self, filename): try: file = open (filename, 'w') file.write (self.get_text (self.get_start_iter(), self.get_end_iter(), False)) file.close() except IOError: return False self.set_modified (False) return True def get_insert_iter (self): return self.get_iter_at_mark (self.get_insert()) # private: def do_insert_text (self, iter, text, length): if not self.ignore_event: action = ('i', iter.get_offset(), text) self.do_stack [self.do_stack_ptr:] = [action] self.do_stack_ptr += 1 gtk.TextBuffer.do_insert_text (self, iter, text, length) def do_delete_range (self, start_it, end_it): if not self.ignore_event: action = ('d', start_it.get_offset(), self.get_text (start_it, end_it, False)) self.do_stack [self.do_stack_ptr:] = [action] self.do_stack_ptr += 1 gtk.TextBuffer.do_delete_range (self, start_it, end_it) def do (self, action, undo): iter = self.get_iter_at_offset (action[1]) if (action[0] == 'd' and undo) or (action[0] == 'i' and not undo): self.ignore_event = True self.insert (iter, action[2]) self.ignore_event = False else: end_iter = self.get_iter_at_offset (action[1] + len (action[2])) self.ignore_event = True self.delete (iter, end_iter) self.ignore_event = False gobject.type_register (TextBufferExt) # Extends GtkTextBuffer (actually our TextBufferExt) to add Editor-specific # functionality class EditorBuffer (TextBufferExt): def __init__ (self, editor): TextBufferExt.__init__(self) self.create_tag("comment", foreground = "darkgrey", style = pango.STYLE_OBLIQUE) self.create_tag("assign", foreground = "darkred") # eg: function: self.create_tag("instruction", weight = pango.WEIGHT_BOLD) # eg: loadn self.create_tag("error", underline = pango.UNDERLINE_ERROR) self.connect_after ("notify::cursor-position", self.cursor_moved_cb) self.cursor_line = 0 self.line_edited = False # was current line edited? self.editor = editor # cuts the line into [(word, start_iter, end_iter), ...] class Split: def __init__ (self, word, start_it, end_it): self.word = word self.start_it = start_it self.end_it = end_it def split_line (self, line): iter = self.get_iter_at_line (line) if iter.is_end(): return None splits = [] while not iter.ends_line(): while is_blank (iter.get_char()) and not iter.ends_line(): iter.forward_char() if iter.ends_line(): break start_iter = iter.copy() while not is_blank (iter.get_char()): iter.forward_char() word = start_iter.get_text (iter).encode() splits += [EditorBuffer.Split (word, start_iter, iter.copy())] return splits def remove_line_tags (self, line): line_iter = self.get_iter_at_line (line) if line_iter.ends_line(): return # blank line -- you'd cross to next line_end_iter = line_iter.copy() line_end_iter.forward_to_line_end() self.remove_all_tags (line_iter, line_end_iter) def is_word_register (self, word): if word == None: return False if len (word) < 2: return False if word[0] != 'r' and word[0] != 'R': return False if len (word) == 2: if word[1] == 's' or word[1] == 'S' or word[1] == 'f' or word[1] == 'F': return True for i in xrange (1, len (word)): if word[i] < '0' or word[i] > '9': return False return True # as-you-type highlighting. Iterates every line touched. def apply_highlight (self, start_line, end_line): line = start_line while line <= end_line: splits = self.split_line (line) if splits == None: break self.remove_line_tags (line) line += 1 length = len (splits) if length == 0: continue comment = None for i in xrange (len (splits)): if splits[i].word[0] == '#': comment = splits[i] length = i break address = None instr = None args = [None, None] args_nb = 0 i = 0 if splits[i].word[-1] == ':': address = splits[i] i += 1 if length > i: instr = splits[i] i += 1 args_nb = length - i if args_nb >= 1: args[0] = splits[i] if args_nb >= 2: args[1] = splits[i+1] if address != None: end_it = address.end_it.copy() end_it.backward_char() # don't highlight the ':' self.apply_tag_by_name ("assign", address.start_it, end_it) match_instr = False if instr != None: for categories in inst: for i in categories: if instr.word == i: match_instr = True self.apply_tag_by_name ("instruction", instr.start_it, instr.end_it) if comment != None: self.apply_tag_by_name ("comment", comment.start_it, splits[-1].end_it) if line-1 != self.get_insert_iter().get_line() and (address != None or instr != None) and self.editor.mode.mode == Editor.Mode.EDIT: error = not match_instr or args_nb > 2 if not error: # arguments semantics: ' ' - none, 'r' - register, 'n' - non-register error_inst = ((' ',' '), ('n',' '), ('r',' '), ('r','r'), ('n','r'), ('r','n')) for i in xrange (6): for w in inst[i]: if w == instr.word: for j in xrange(2): if error_inst[i][j] == ' ': error = error or args[j] != None elif args[j] == None: error = True elif error_inst[i][j] == 'r': error = error or not self.is_word_register (args[j].word) elif error_inst[i][j] == 'n': error = error or self.is_word_register (args[j].word) if error: start_it = splits[0].start_it end_it = splits[length-1].end_it self.apply_tag_by_name ("error", start_it, end_it) def cursor_moved_cb (self, buffer, pos_ptr): line = self.get_insert_iter().get_line() if line != self.cursor_line: if self.line_edited: self.apply_highlight (self.cursor_line, self.cursor_line) self.line_edited = False self.cursor_line = line def do_insert_text (self, iter, text, length): TextBufferExt.do_insert_text (self, iter, text, length) self.line_edited = True # as-you-type highlighting start = iter.copy() start.set_offset (iter.get_offset() - length) self.apply_highlight (start.get_line(), iter.get_line()) # simple auto-identation; if the user typed return, apply the same # identation of the previous line if length == 1 and text == "\n": start_it = iter.copy() if start_it.backward_line(): end_it = start_it.copy() while end_it.get_char() == ' ' or end_it.get_char() == '\t': end_it.forward_char() if start_it.compare (end_it) != 0: # there is identation ident = self.get_text (start_it, end_it) self.insert (iter, ident) def do_delete_range (self, start_it, end_it): TextBufferExt.do_delete_range (self, start_it, end_it) self.apply_highlight (start_it.get_line(), end_it.get_line()) # hooks for emacs-like region mark (ctrl+space) def cursor_moved (self, view, step_size, count, extend_selection): mark = self.get_mark ("emacs-mark") if mark: self.select_range (self.get_iter_at_mark (self.get_insert()), self.get_iter_at_mark (mark)) def do_changed (self): # disable emacs' mark region gtk.TextBuffer.do_changed (self) mark = self.get_mark ("emacs-mark") if mark: self.delete_mark (mark) # The Editor widget, an extension over gtk.TextView to support eg. line numbering class Editor (gtk.TextView): class Mode(object): EDIT = 0 RUN = 1 def __init__ (self, editor): self.editor = editor # Save normal/sensitive base color so we can mess with that self.normal_color = editor.style.base [gtk.STATE_NORMAL] self.insensitive_color = editor.style.base [gtk.STATE_INSENSITIVE] self.line_color = None self.set_mode (None) def set_mode (self, vpu): if vpu == None: self.mode = self.EDIT self.alternative_numbering = None self.fixed_line = -1 self.editor.breakpoints = [] else: if self.mode == self.RUN: self.editor.reload_breakpoints (vpu) self.mode = self.RUN self.alternative_numbering = {} for i in xrange (len (vpu.lines)): self.alternative_numbering [vpu.lines[i]-1] = i # We don't want to set the editor insensitive to allow users # to do selections and that. So we mimic half of it. editable = self.mode == self.EDIT self.editor.set_editable (editable) self.editor.set_cursor_visible (editable) if editable: self.editor.modify_base (gtk.STATE_NORMAL, self.normal_color) else: self.editor.modify_base (gtk.STATE_NORMAL, self.insensitive_color) def set_current_line (self, line): if self.mode == self.EDIT: self.fixed_line = -1 if line >= 0: buffer = self.editor.get_buffer() it = buffer.get_iter_at_line (line) buffer.place_cursor (it) # make line visible self.editor.scroll_to_iter (it, 0.10) self.fixed_line = line-1 self.editor.queue_draw() # update line highlight def set_current_line_color (self, color): if color == "white": color = None self.line_color = color self.editor.queue_draw() def get_current_line (self, window): if self.mode == self.EDIT: buffer = self.editor.get_buffer() iter = buffer.get_iter_at_mark (buffer.get_insert()) curline = iter.get_line() fill_gc = self.editor.style.bg_gc [gtk.STATE_NORMAL] stroke_gc = None else: curline = self.fixed_line color = get_tone_color (self.editor.style, 255) if self.line_color != None: clr = self.line_color color = gtk.gdk.color_parse (clr) fill_gc = window.new_gc() fill_gc.set_rgb_fg_color (color) color = get_tone_color (self.editor.style, 150) if self.line_color != None: clr = self.line_color + "4" color = gtk.gdk.color_parse (clr) stroke_gc = window.new_gc() stroke_gc.set_rgb_fg_color (color) return (curline, fill_gc, stroke_gc) def get_line_number (self, line): if self.alternative_numbering: try: line = self.alternative_numbering [line] except: line = -1 else: line = line+1 return line def __init__ (self, parent): buffer = EditorBuffer (self) gtk.TextView.__init__ (self, buffer) self.main_parent = parent self.set_tabs (pango.TabArray (4, False)) set_monospace_font (self) self.set_wrap_mode (gtk.WRAP_WORD_CHAR) self.set_left_margin (1) font_desc = self.get_pango_context().get_font_description() metrics = self.get_pango_context().get_metrics (font_desc, None) self.digit_width = pango.PIXELS (metrics.get_approximate_digit_width()) self.digit_height = pango.PIXELS (metrics.get_ascent()) self.digit_height += pango.PIXELS (metrics.get_descent()) self.margin_digits = 99 # to force a margin calculation self.text_changed (self.get_buffer()) # sets the numbering margin self.do_stack = [] # of type [ ('i', 30, "text"), ('d', 20,"other") ] # for re/undo self.do_stack_ptr = 0 # printing setup self.settings = None # editor mode: edit, run, or error self.mode = Editor.Mode (self) buffer.connect ("changed", self.text_changed) self.connect_after ("move-cursor", buffer.cursor_moved) # for the emacs mark def get_text (self): buffer = self.get_buffer() return buffer.get_text (buffer.get_start_iter(), buffer.get_end_iter(), False) def do_expose_event (self, event): # draw command curline, fill_gc, stroke_gc = self.mode.get_current_line (event.window) # left window -- draw line numbering window = self.get_window (gtk.TEXT_WINDOW_LEFT) if event.window == window: visible_text = self.get_visible_rect() iter = self.get_iter_at_location (visible_text.x, visible_text.y) layout = pango.Layout (self.get_pango_context()) last_loop = False while True: # a do ... while would be nicer :/ rect = self.get_iter_location (iter) x, y = self.buffer_to_window_coords (gtk.TEXT_WINDOW_LEFT, rect.x, rect.y) if y > event.area.y + event.area.height: break if y + self.digit_height > event.area.y: line = self.mode.get_line_number (iter.get_line()) # draw a half arc at the numbering window to finish current line # rectangle nicely. if iter.get_line() == curline and stroke_gc != None: w = self.get_border_window_size (gtk.TEXT_WINDOW_LEFT) h = rect.height window.draw_arc (fill_gc, True, 0, y, w, h, 90*64, 180*64) window.draw_arc (stroke_gc, False, 0, y, w, h-1, 90*64, 180*64) window.draw_rectangle (fill_gc, True, w/2, y+1, w/2, h-1) window.draw_line (stroke_gc, w/2, y, w, y) window.draw_line (stroke_gc, w/2, y+h-1, w, y+h-1) # draw a circle for break points if self.mode.mode == Editor.Mode.RUN: if iter.get_line() in self.breakpoints: color = gtk.gdk.Color (237 << 8, 146 << 8, 146 << 8, 0) gc = event.window.new_gc() gc.set_rgb_fg_color (color) color = gtk.gdk.Color (180 << 8, 110 << 8, 110 << 8, 0) out_gc = event.window.new_gc() out_gc.set_rgb_fg_color (color) w = self.get_border_window_size (gtk.TEXT_WINDOW_LEFT) h = rect.height window.draw_arc (gc, True, 0, y, w, h, 0, 360*64) window.draw_arc (out_gc, False, 0, y, w-1, h-1, 0, 360*64) if line >= 0: text = str (line).rjust (self.margin_digits, " ") # align at right if iter.get_line() == curline: text = "" + text + "" if self.mode.mode != Editor.Mode.EDIT: text = "" + text + "" layout.set_markup (text) self.style.paint_layout (window, gtk.STATE_NORMAL, False, event.area, self, "", 2, y, layout) if last_loop: break if not iter.forward_line(): last_loop = True # text window -- highlight current line window = self.get_window (gtk.TEXT_WINDOW_TEXT) if event.window == window: # do the current line highlighting now iter = self.get_buffer().get_iter_at_line (curline) y, h = self.get_line_yrange (iter) x, y = self.buffer_to_window_coords (gtk.TEXT_WINDOW_TEXT, 0, y) w = self.allocation.width """ rect = self.get_iter_location (iter) x, y = self.buffer_to_window_coords (gtk.TEXT_WINDOW_TEXT, 0, rect.y) w = self.allocation.width h = rect.height """ window.draw_rectangle (fill_gc, True, x, y, w, h) if stroke_gc != None: window.draw_line (stroke_gc, x, y, w, y) window.draw_line (stroke_gc, x, y + h - 1, w, y + h - 1) return gtk.TextView.do_expose_event (self, event) # button pressed on numbering pane -- move cursor to that line # for two clicks, set break point # parent is a hook to be able to access Interface def do_button_press_event (self, event): gtk.TextView.do_button_press_event (self, event) parent = self.main_parent if event.window == self.get_window (gtk.TEXT_WINDOW_LEFT): x, y = self.window_to_buffer_coords (gtk.TEXT_WINDOW_LEFT, int (event.x), int (event.y)) it = self.get_iter_at_location (x, y) self.get_buffer().place_cursor (it) if event.type == gtk.gdk._2BUTTON_PRESS and self.mode.mode == Editor.Mode.RUN: line = it.get_line() vpu = parent.vpu.vpu # see if there is already one -- if so, remove it if line in self.breakpoints: # remove it try: i = vpu.lines.index (line+1) except ValueError: parent.message.write ("%s %s" % ("Cannot clear a break point in line", line+1), "white") else: try: vpu.clearbreak (i) except: parent.message.write ("Error: %s, %s" % (sys.exc_type, sys.exc_value), "red") else: self.breakpoints.remove (line) else: # add break point try: i = vpu.lines.index (line+1) except ValueError: parent.message.write ("%s %s" % ("Cannot set a break point in line", line+1), "white") else: try: vpu.setbreak (i) except: parent.message.write ("Error: %s, %s" % (sys.exc_type, sys.exc_value), "red") else: self.breakpoints.append (line) def reload_breakpoints (self, vpu): for i in self.breakpoints: pt = vpu.lines.index (i+1) vpu.setbreak (pt) # we use this so we know when lines are inserted or removed and change the # line numbering border accordingly def text_changed (self, buffer): digits = max (digits_on (buffer.get_line_count()), 2) if digits != self.margin_digits: self.margin_digits = digits margin = (self.digit_width * digits) + 4 self.set_border_window_size (gtk.TEXT_WINDOW_LEFT, margin) # Printing support def print_text (self, parent_window, title): print_data = self.PrintData() print_data.header_title = title print_op = gtk.PrintOperation() if self.settings != None: print_op.set_print_settings (self.settings) print_op.connect ("begin-print", self.print_begin_cb, print_data) print_op.connect ("draw-page", self.print_page_cb, print_data) try: res = print_op.run (gtk.PRINT_OPERATION_ACTION_PRINT_DIALOG, parent_window) except gobject.GError, ex: error_dialog = gtk.MessageDialog(main_window, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Error printing file:\n%s" % str (ex)) error_dialog.run() error_dialog.destroy() else: if res == gtk.PRINT_OPERATION_RESULT_APPLY: self.settings = print_op.get_print_settings() class PrintData: layout = None page_breaks = None header_title = None header_height = 0 header_layout = None def print_begin_cb (self, operation, context, print_data): width = context.get_width() height = context.get_height() print_data.layout = context.create_pango_layout() print_data.layout.set_font_description (pango.FontDescription ("Monospace 12")) print_data.layout.set_width (int (width * pango.SCALE)) # create a layout based on the text with applied tags for printing it = self.get_buffer().get_start_iter() text = "" tags = self.get_buffer().get_tag_table() comment_tag = tags.lookup ("comment") assign_tag = tags.lookup ("assign") instruction_tag = tags.lookup ("instruction") while not it.is_end(): if it.ends_tag (None): text += "" if it.starts_line(): text += "" text += str (it.get_line()+1).rjust (self.margin_digits, " ") text += " " if it.begins_tag (comment_tag): text += "" if it.begins_tag (assign_tag): text += "" if it.begins_tag (instruction_tag): text += "" text += it.get_char() it.forward_char() print_data.layout.set_markup (text) print_data.header_layout = context.create_pango_layout() print_data.header_layout.set_font_description (pango.FontDescription ("Sans 12")) print_data.header_layout.set_width (int (width * pango.SCALE)) print_data.header_layout.set_text ("title") header_height = print_data.header_layout.get_extents()[1][3] / 1024.0 print_data.header_height = header_height + 10 num_lines = print_data.layout.get_line_count() page_breaks = [] page_height = 0 for line in xrange (num_lines): layout_line = print_data.layout.get_line (line) ink_rect, logical_rect = layout_line.get_extents() lx, ly, lwidth, lheight = logical_rect line_height = lheight / 1024.0 if page_height + line_height + header_height > height: page_breaks.append (line) page_height = 0 page_height += line_height operation.set_n_pages (len (page_breaks) + 1) print_data.page_breaks = page_breaks def print_page_cb (self, operation, context, page_nr, print_data): assert isinstance (print_data.page_breaks, list) if page_nr == 0: start = 0 else: start = print_data.page_breaks [page_nr - 1] try: end = print_data.page_breaks [page_nr] except IndexError: end = print_data.layout.get_line_count() cr = context.get_cairo_context() cr.set_source_rgb(0, 0, 0) # print page header header_height = print_data.header_height header_layout = print_data.header_layout cr.move_to (0, header_height-4) cr.line_to (context.get_width(), header_height-4) cr.stroke() if print_data.header_title != None: cr.move_to (6, 3) header_layout.set_text (print_data.header_title) cr.show_layout (header_layout) header_layout.set_text ("Page %s of %s" % (page_nr+1, len (print_data.page_breaks)+1)) x = header_layout.get_extents()[1][2] / 1024.0 x = context.get_width() - x cr.move_to (x-6, 3) cr.show_layout (header_layout) # print body -- the text cr.set_source_rgb (0, 0, 0) i = 0 start_pos = 0 iter = print_data.layout.get_iter() while True: if i >= start: line = iter.get_line() _, logical_rect = iter.get_line_extents() lx, ly, lwidth, lheight = logical_rect baseline = iter.get_baseline() if i == start: start_pos = ly / 1024.0; cr.move_to (lx / 1024.0, baseline / 1024.0 - start_pos + header_height) cr.show_layout_line (line) i += 1 if not (i < end and iter.next_line()): break gobject.type_register (Editor) # A very-visible colored-enabled message label # NOTE: gtk.Label doesn't have a background and we shouldn't use a gtk.EventBox # container because gtk-qt-engine doesn't honor its background, so we draw it # ourselves. class MessageLabel (gtk.Label): def __init__ (self): gtk.Label.__init__ (self) self.set_padding (0, 6) self.set_line_wrap (True) font = pango.FontDescription() font.set_weight (pango.WEIGHT_BOLD) font.set_size (12 * pango.SCALE) self.modify_font (font) def write (self, text, bg_color): if text == "": # avoids asking for different sizes... text = " " if self.window != None: self.set_text (text) self.modify_bg (gtk.STATE_NORMAL, gtk.gdk.color_parse (bg_color)) # if we want to also have a text_color parameter: #self.modify_fg (gtk.STATE_NORMAL, gtk.gdk.color_parse (text_color)) def do_expose_event (self, event): self.style.paint_box (self.window, gtk.STATE_NORMAL, gtk.SHADOW_OUT, event.area, self, None, self.allocation.x, self.allocation.y, self.allocation.width, self.allocation.height) return gtk.Label.do_expose_event (self, event) gobject.type_register (MessageLabel) # A GtkEntry that only accepts numbers class DigitEntry (gtk.Entry): def __init__ (self, can_be_negative = False, default_number = 0): gtk.Entry.__init__ (self) self.can_be_negative = can_be_negative self.set_value (default_number) self.connect ("insert-text", self.insert_text_cb) self.connect ("focus-out-event", self.focus_out_event_cb) def set_value (self, number): self.set_text (str (number)) def get_value (self): try: value = int (self.get_text()) except ValueError: return 0 return value def insert_text_cb (self, editable, text, length, pos_ptr): pos = self.get_position() if not ((self.can_be_negative and pos == 0 and text == '-') or text.isdigit()): editable.emit_stop_by_name ("insert_text") gtk.gdk.beep() def focus_out_event_cb (self, widget, event): if self.get_text() == "": self.set_value (0) return False # Explicit ratio horizontal box # Simple stuff: don't care for widgets sizes class RatioHBox (gtk.Container): def __init__ (self, padding): gtk.Container.__init__ (self) self.set_flags (gtk.NO_WINDOW) self.set_redraw_on_allocate (False) self.padding = padding self.sum_ratios = 0 self.children = [] # of (gtk.Widget, ratio) def pack (self, child, ratio): self.children.append ((child, ratio)) self.sum_ratios += ratio child.set_parent (self) def do_add (self, child): self.pack (child, 1) def do_remove (self, child): for i in self.children: if i[0] == child: self.sum_ratios -= i[1] self.children.remove (i) child.unparent() break def do_child_type (self): return gtk.TYPE_WIDGET def do_forall (self, include_internals, callback, callback_data): for i in self.children: callback (i[0], callback_data) def do_size_request (self, req): req.width = req.height = 0 for child, ratio in self.children: size = child.size_request() req.height = max (req.height, size[1]) def do_size_allocate (self, allocate): child_alloc = gtk.gdk.Rectangle (allocate.x, allocate.y, 0, allocate.height) width = allocate.width - (len (self.children)-1)*self.padding for child, ratio in self.children: child_alloc.width = (width * ratio) / self.sum_ratios child.size_allocate (child_alloc) child_alloc.x += child_alloc.width + self.padding gobject.type_register (RatioHBox) # The setup dialog def read_config(): config = ConfigParser.ConfigParser () config.read (APOO_CONFIG_FILE) global shortcuts_style, mirror_memory if config.has_option ("appearance", "keys-shortcuts"): shortcuts_style = config.get ("appearance", "keys-shortcuts") if config.has_option ("appearance", "memory-mirror"): mirror_memory = config.get ("appearance", "memory-mirror") global registers_nb, ram_size, max_steps, input_output, output_ascii, output_cr if config.has_option ("vpu", "registers-nb"): registers_nb = config.getint ("vpu", "registers-nb") if config.has_option ("vpu", "ram-size"): ram_size = config.getint ("vpu", "ram-size") if config.has_option ("vpu", "max-steps"): max_steps = config.getint ("vpu", "max-steps") if config.has_option ("vpu", "input-output-mem"): input_output = config.getint ("vpu", "input-output-mem") if config.has_option ("vpu", "output-ascii-mem"): output_ascii = config.getint ("vpu", "output-ascii-mem") if config.has_option ("vpu", "output-cr-mem"): output_cr = config.getint ("vpu", "output-cr-mem") global default_dir if config.has_option ("session", "default-dir"): default_dir = config.get ("session", "default-dir") def write_config(): config = ConfigParser.ConfigParser () config.add_section ("appearance") config.set ("appearance", "keys-shortcuts", shortcuts_style) config.set ("appearance", "memory-mirror", mirror_memory) config.add_section ("vpu") config.set ("vpu", "registers-nb", int (registers_nb)) config.set ("vpu", "ram-size", int (ram_size)) config.set ("vpu", "max-steps", int (max_steps)) config.set ("vpu", "input-ouput-mem", int (input_output)) config.set ("vpu", "output-ascii-mem", int (output_ascii)) config.set ("vpu", "output-cr-mem", int (output_cr)) if default_dir != None: config.add_section ("session") config.set ("session", "default-dir", default_dir) file = open (APOO_CONFIG_FILE, 'w') config.write (file) file.close() class Preferences (gtk.Dialog): def __init__ (self): gtk.Dialog.__init__ (self, "Preferences", None, 0, (gtk.STOCK_REVERT_TO_SAVED, 1, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) self.set_default_response (gtk.RESPONSE_CLOSE) self.set_has_separator (False) self.set_resizable (False) look_feel_box = gtk.VBox (False, 6) vpu_box = gtk.VBox (False, 6) # key shortcuts stuff self.desktop_keys = gtk.RadioButton (label = "_Desktop definitions") self.emacs_keys = gtk.RadioButton (label = "_Emacs defaults", group = self.desktop_keys) # set this data, so we can differ them keys_box = gtk.VBox (True, 2) keys_box.pack_start (self.desktop_keys) keys_box.pack_start (self.emacs_keys) if shortcuts_style == "emacs": self.emacs_keys.set_active (True) # the other is the default anyway self.desktop_keys.connect ("toggled", self.desktop_keys_cb) self.emacs_keys.connect ("toggled", self.emacs_keys_cb) # mirror memory stuff self.mirror_title = gtk.CheckButton ("_Mirror Memory") self.mirror_title.child.set_use_markup (True) self.mirror_hor = gtk.RadioButton (label = "_Horizontally") self.mirror_ver = gtk.RadioButton (label = "_Vertically", group = self.mirror_hor) mirror_box = gtk.VBox (True, 2) mirror_box.pack_start (self.mirror_hor) mirror_box.pack_start (self.mirror_ver) self.mirror_frame = self.create_frame (None, mirror_box) self.mirror_frame.set_label_widget (self.mirror_title) if mirror_memory == "no": self.mirror_frame.child.set_sensitive (False) else: self.mirror_title.set_active (True) if mirror_memory == "ver": self.mirror_ver.set_active (True) self.mirror_title.connect ("toggled", self.mirror_memory_cb) self.mirror_hor.connect ("toggled", self.mirror_memory_cb) self.mirror_ver.connect ("toggled", self.mirror_memory_cb) look_feel_box.pack_start (self.create_frame ("Key Shortcuts", keys_box), False) look_feel_box.pack_start (self.mirror_frame, False) self.regs_entry = DigitEntry (False, registers_nb) self.ram_entry = DigitEntry (False, ram_size) self.steps_entry = DigitEntry(False, max_steps) self.in_out_entry = DigitEntry (False, input_output) self.ascii_out_entry = DigitEntry (False, output_ascii) self.cr_out_entry = DigitEntry (False, output_cr) self.regs_entry.connect_after ("changed", self.regs_changed_cb) self.ram_entry.connect_after ("changed", self.ram_changed_cb) self.steps_entry.connect_after ("changed", self.steps_changed_cb) self.in_out_entry.connect_after ("changed", self.in_out_changed_cb) self.ascii_out_entry.connect_after ("changed", self.ascii_out_changed_cb) self.cr_out_entry.connect_after ("changed", self.cr_out_changed_cb) cpu_grid = self.create_grid ("Machine Processor", [ ("_Number of registers", self.regs_entry), ("_RAM size", self.ram_entry), ("_Maximum steps", self.steps_entry) ] ) mem_grid = self.create_grid ("Memory Mapping", [ ("_Integer input/output", self.in_out_entry), ("_ASCII output", self.ascii_out_entry), ("_CR output", self.cr_out_entry) ] ) info_box = gtk.HBox (False, 6) info_box.set_border_width (6) image = gtk.Image() image.set_from_stock (gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON) label = gtk.Label ("Changes will take effect on Load.") info_box.pack_start (image, False) info_box.pack_start (label, False) info_align = gtk.Alignment (0.5, 0, 0, 0) info_align.add (info_box) vpu_box.pack_start (cpu_grid, False) vpu_box.pack_start (mem_grid, False) vpu_box.pack_start (info_align, False) self.notebook = gtk.Notebook() self.notebook.append_page (look_feel_box, gtk.Label ("_Look 'n Feel")) self.notebook.append_page (vpu_box, gtk.Label ("_VPU")) # we need to set the mnemonic in effect manually for i in self.notebook.get_children(): label = self.notebook.get_tab_label (i) label.set_use_underline (True) label.set_mnemonic_widget (i) self.notebook.set_border_width (6) self.notebook.show_all() self.vbox.pack_start (self.notebook) self.connect ("response", self.response) self.connect ("delete-event", self.hide_on_delete) def response (self, dialog, response_id): if response_id == gtk.RESPONSE_NONE or response_id == gtk.RESPONSE_CLOSE: dialog.hide() if response_id == 1: # revert # load defaults if SHORTCUTS_STYLE == "emacs": self.emacs_keys.set_active (True) else: self.desktop_keys.set_active (True) if MIRROR_MEMORY == "no": self.mirror_title.set_active (False) else: if MIRROR_MEMORY == "ver": self.mirror_ver.set_active (True) else: self.mirror_hor.set_active (True) self.mirror_title.set_active (True) self.regs_entry.set_value (REGISTERS_NB) self.ram_entry.set_value (RAM_SIZE) self.steps_entry.set_value (MAX_STEPS) self.in_out_entry.set_value (INPUT_OUTPUT) self.ascii_out_entry.set_value (OUTPUT_ASCII) self.cr_out_entry.set_value (OUTPUT_CR) def regs_changed_cb (self, entry): global registers_nb registers_nb = entry.get_value() return False def ram_changed_cb (self, entry): global ram_size ram_size = entry.get_value() return False def steps_changed_cb (self, entry): global max_steps max_steps = entry.get_value() return False def in_out_changed_cb (self, entry): global input_output input_output = entry.get_value() return False def ascii_out_changed_cb (self, entry): global output_ascii output_ascii = entry.get_value() return False def cr_out_changed_cb (self, entry): global output_cr output_cr = entry.get_value() return False def shortcut_keys_changed (self): for i in windows: i.load_menu() def desktop_keys_cb (self, button): global shortcuts_style if button.get_active(): shortcuts_style = "desktop" self.shortcut_keys_changed() def emacs_keys_cb (self, button): global shortcuts_style if button.get_active(): shortcuts_style = "emacs" self.shortcut_keys_changed() def mirror_memory_cb (self, widget): global mirror_memory if widget == self.mirror_title: mirror_memory = "no" if widget.get_active(): if self.mirror_hor.get_active(): widget = self.mirror_hor else: widget = self.mirror_ver self.mirror_frame.child.set_sensitive (widget.get_active()) if widget == self.mirror_hor: mirror_memory = "hor" elif widget == self.mirror_ver: mirror_memory = "ver" for i in windows: for j in i.notebook.get_children(): j.create_memory_table() # to cut down on code size def create_frame (self, title, widget): if title == None: frame = gtk.Frame() else: frame = gtk.Frame ("" + title + "") frame.get_label_widget().set_use_markup (True) frame.set_shadow_type (gtk.SHADOW_NONE) frame.set_border_width (6) # the sole purpose of the box is to set border and padding box = gtk.HBox (False, 0) box.pack_start (widget, padding = 11) box.set_border_width (4) frame.add (box) return frame def create_grid (self, title, entries): table = gtk.Table (2, len (entries)) for i in entries: label = gtk.Label (i[0] + ":") widget = i[1] row = entries.index (i) table.attach (label, 0, 1, row, row+1, xoptions = gtk.FILL, yoptions = gtk.FILL) table.attach (widget, 1, 2, row, row+1, xoptions = gtk.FILL, yoptions = gtk.FILL) label.set_use_underline (True) label.set_mnemonic_widget (widget) label.set_alignment (0.0, 0.5) table.set_col_spacings (6) table.set_row_spacings (6) return self.create_frame (title, table) preferences_dialog = None def preferences_show (window): global preferences_dialog if preferences_dialog == None: preferences_dialog = Preferences() preferences_dialog.set_transient_for (window) preferences_dialog.notebook.set_current_page (0) preferences_dialog.present() ## The table stack pointer renderer class CellRendererStackPointer (gtk.GenericCellRenderer): ARROW_WIDTH = ARROW_HEIGHT = 8 # pointer enum POINTER_NONE = 0 POINTER_RF = 1 POINTER_MIDDLE = 2 POINTER_RS = 3 POINTER_SAME = 4 __gproperties__ = { 'pointer': (gobject.TYPE_INT, 'pointer property', 'Pointer relatively to the data being pointed to.', 0, 4, POINTER_NONE, gobject.PARAM_READWRITE), } def __init__(self): self.__gobject_init__() self.pointer = self.POINTER_NONE def do_get_property(self, pspec): if pspec.name == "pointer": return self.pointer else: raise AttributeError, 'unknown property %s' % pspec.name def do_set_property (self, pspec, value): if pspec.name == "pointer": self.pointer = value self.notify ("pointer") else: raise AttributeError, 'unknown property %s' % pspec.name def create_layout (self, widget, ptr): layout = pango.Layout (widget.get_pango_context()) if ptr == self.POINTER_RF: layout.set_text ("rf") elif ptr == self.POINTER_RS: layout.set_text ("rs") else: layout.set_text ("r") return layout def do_render (self, window, widget, bg_area, cell_area, expose_area, flags): if self.pointer == self.POINTER_NONE: return bg_gc = window.new_gc() bg_gc.set_rgb_fg_color (get_tone_color (widget.style, 255)) fg_gc = window.new_gc() fg_gc.set_rgb_fg_color (get_tone_color (widget.style, 140)) fg_gc.set_line_attributes (2, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER) # pointer drawing x = cell_area.x y = bg_area.y w = cell_area.width # self.ARROW_WIDTH h = bg_area.height if self.pointer == self.POINTER_MIDDLE: window.draw_line (fg_gc, x + w/2, y, x + w/2, y+h) if self.pointer != self.POINTER_MIDDLE: x = cell_area.x w = self.ARROW_WIDTH y = cell_area.y + cell_area.height/2 h = self.ARROW_HEIGHT points = [ (x, y), (x + w, y - h/2), (x + w, y + h/2) ] window.draw_polygon (bg_gc, True, points) window.draw_polygon (fg_gc, False, points) layout = self.create_layout (widget, self.pointer) lw, lh = layout.get_pixel_size() lx = cell_area.x + self.ARROW_WIDTH + 4 ly = (cell_area.height - lh)/2 + cell_area.y widget.style.paint_layout (window, gtk.STATE_NORMAL, True, expose_area, widget, None, lx, ly, layout) def do_get_size (self, widget, cell_area): layout = self.create_layout (widget, self.POINTER_RS) w, h = layout.get_pixel_size() h = max (h, self.ARROW_HEIGHT) w += self.ARROW_WIDTH + 6 return 0, 0, w, h # Doesn't need to be registered, since it is a PyGtk instance #gobject.type_register (CellRendererStackPointer) class ButtonWithSpin (gtk.Button): def __init__ (self, label): gtk.Button.__init__ (self, label) self.label = label self.value = 1 self.popup = gtk.Menu() for i in xrange (1,21): item = gtk.MenuItem (str (i)) item.connect ("activate", self.popup_menu_item_cb, i) item.show() self.popup.append (item) self.popup.attach_to_widget (self, None) def get_value (self): return self.value def set_value (self, value): self.value = value label = self.label + " " + str (value) self.set_label (label) def popup_menu_item_cb (self, item, value): self.set_value (value) def do_button_press_event (self, event): gtk.Button.do_button_press_event (self, event) if event.button == 3: self.popup.popup (None, None, None, 3, event.time) gobject.type_register (ButtonWithSpin) ## VPU Model class VpuModel: class ListModel (gtk.GenericTreeModel): def __init__ (self, list): gtk.GenericTreeModel.__init__ (self) self.list = list def on_get_flags (self): return gtk.TREE_MODEL_ITERS_PERSIST|gtk.TREE_MODEL_LIST_ONLY def on_get_iter (self, path): index = path[0] if index < len (self.list): return index return None def on_get_path (self, index): return (index,) def on_iter_next (self, index): if index+1 < len (self.list): return index+1 return None def on_iter_has_child (self, iter): return False def on_iter_parent(self, child): return None def on_iter_n_children (self, iter): if iter == None: len (self.list) return 0 def on_iter_nth_child (self, parent, n): if n < len (self.list): return [n] return None def on_iter_children (self, parent): return self.on_iter_nth_child (parent, 0) class RamModel (ListModel): def __init__ (self, vpu): VpuModel.ListModel.__init__ (self, vpu.RAM) self.vpu = vpu INDEX_COL = 0 LABEL_COL = 1 VALUE_COL = 2 INDEX_COLOR_COL = 3 LABEL_COLOR_COL = 4 VALUE_COLOR_COL = 5 BACKGROUND_COLOR_COL = 6 REGS_POINTER_COL = 7 def on_get_n_columns (self): return 8 def on_get_column_type (self, col): if col == self.INDEX_COL: return str elif col == self.LABEL_COL: return str elif col == self.VALUE_COL: return str elif col == self.INDEX_COLOR_COL: return str elif col == self.LABEL_COLOR_COL: return str elif col == self.VALUE_COLOR_COL: return str elif col == self.BACKGROUND_COLOR_COL: return gtk.gdk.Color elif col == self.REGS_POINTER_COL: return int def on_get_value (self, index, col): if col == self.INDEX_COL: return str (index) elif col == self.LABEL_COL: label = reverse_lookup (self.vpu.labelm, index) if label == None: label = "" return label elif col == self.VALUE_COL: return str (self.list [index]) elif col == self.INDEX_COLOR_COL: if index in self.vpu.mem_changed: return "red" return "blue" elif col == self.LABEL_COLOR_COL: if index in self.vpu.mem_changed: return "red" return "darkred" elif col == self.VALUE_COLOR_COL: if index in self.vpu.mem_changed: return "red" return "black" elif col == self.BACKGROUND_COLOR_COL: rf = self.vpu.reg [-2] rs = self.vpu.reg [-1] if index < rf or index > rs: if index % 2 == 1: return get_color (242, 171, 171) return get_color (255, 180, 180) if index % 2 == 1: return get_color (238, 238, 238) return get_color (255, 255, 255) elif col == self.REGS_POINTER_COL: if len (self.vpu.reg) >= 2: rf = self.vpu.reg [-2] rs = self.vpu.reg [-1] if index == rf: if index == rs: return CellRendererStackPointer.POINTER_SAME return CellRendererStackPointer.POINTER_RF if index == rs: return CellRendererStackPointer.POINTER_RS if index > rf and index < rs: return CellRendererStackPointer.POINTER_MIDDLE return CellRendererStackPointer.POINTER_NONE def sync (self): changed = {} for i in self.vpu.mem_changed: changed[i] = True for i in self.vpu.last_mem_changed: changed[i] = True rf = self.vpu.reg [-2] rs = self.vpu.reg [-1] last_rf = self.vpu.last_reg [-2] last_rs = self.vpu.last_reg [-1] if last_rs != rs or last_rf != rf: for i in xrange (min (last_rf, last_rs), max (last_rf, last_rs)+1): changed[i] = True for i in xrange (min (rf, rs), max (rf, rs)+1): changed[i] = True for i in changed: if i >= 0: path = (i,) iter = self.get_iter (path) self.row_changed (path, iter) class RegModel (ListModel): def __init__ (self, vpu): VpuModel.ListModel.__init__ (self, vpu.reg) self.vpu = vpu INDEX_COL = 0 LABEL_COL = 1 VALUE_COL = 2 COLOR_COL = 3 def on_get_n_columns (self): return 4 def on_get_column_type (self, col): if col == self.INDEX_COL: return str elif col == self.LABEL_COL: return str elif col == self.VALUE_COL: return str elif col == self.COLOR_COL: return str def on_get_value (self, index, col): if col == self.INDEX_COL: return "R%d" % index elif col == self.LABEL_COL: if self.vpu.nreg >= 2: if index == self.vpu.nreg-2: return "RF" elif index == self.vpu.nreg-1: return "RS" return "" elif col == self.VALUE_COL: return str (self.list [index]) elif col == self.COLOR_COL: if index in self.vpu.reg_changed: return "red" return "black" def sync (self): changed = {} for i in self.vpu.reg_changed: changed[i] = True for i in self.vpu.last_reg_changed: changed[i] = True for i in changed: path = (i, ) iter = self.get_iter (path) self.row_changed (path, iter) class Listener: def set_ram_model (self, model): pass def set_reg_model (self, model): pass def set_ram_scroll (self, path): pass def set_reg_scroll (self, path): pass def set_output_buffer (self, buffer): pass def set_program_counter (self, value): pass def set_timer_counter (self, value): pass def set_message (self, message, status, color): pass def get_program_code (self): pass def __init__ (self, listener): self.listener = listener self.ram_model = None self.reg_model = None def load (self): self.vpu = Vpu (registers_nb, { output_ascii:("val = 0", "self.Inter.output_inst (val, True)"), input_output:("val = self.Inter.input_inst()", "self.Inter.output_inst (val)"), output_cr:("val = 0", "self.Inter.output_inst()") }, self, ram_size) self.vpu.last_reg = self.vpu.reg self.vpu.mem_changed = [] self.vpu.reg_changed = [] self.vpu.last_mem_changed = [] self.vpu.last_reg_changed = [] program = self.listener.get_program_code() try: self.vpu.load (program) except vpuLoadError,error: message = "Parsing Error (Ln %d): %s" % (error.line, error.message) self.listener.set_message (message, "parsing error", "red", error.line) return False except: message = "Parsing Error: %s, %s" % (sys.exc_type, sys.exc_value) self.listener.set_message (message, "parsing error", "red") return False self.listener.set_message ("Program Loaded", "loaded", "white") self.ram_model = VpuModel.RamModel (self.vpu) self.reg_model = VpuModel.RegModel (self.vpu) self.listener.set_ram_model (self.ram_model) self.listener.set_reg_model (self.reg_model) self.output_buffer = gtk.TextBuffer() self.listener.set_output_buffer (self.output_buffer) self.sync() return True def clear (self): self.ram_model = None self.reg_model = None self.output_buffer = None self.listener.set_ram_model (None) self.listener.set_reg_model (None) self.listener.set_output_buffer (None) self.listener.set_program_counter (0) self.listener.set_timer_counter (0) self.vpu = None def sync (self): self.ram_model.sync() self.reg_model.sync() if len (self.vpu.mem_changed) > 0: self.listener.set_ram_scroll ((self.vpu.mem_changed[0],)) if len (self.vpu.reg_changed) > 0: self.listener.set_reg_scroll ((self.vpu.reg_changed[0],)) self.listener.set_program_counter (self.vpu.PC) self.listener.set_timer_counter (self.vpu.time) def advance (self, steps_nb, honor_breakpoint): if self.ram_model == None: return # not loaded self.listener.set_message ("Running", "running", "white") self.vpu.last_mem_changed = self.vpu.mem_changed[:] self.vpu.last_reg_changed = self.vpu.reg_changed[:] step = 0 while True: self.vpu.last_reg = self.vpu.reg[:] self.vpu.mem_changed = [] self.vpu.reg_changed = [] try: mem_changed = self.vpu.step() if mem_changed != (None, None) and not mem_changed[0] in self.vpu.mem_changed: self.vpu.mem_changed.append (mem_changed[0]) if step > max_steps: raise TooManySteps (step) except OutOfMemory, error: message = "%s: memory address %s not reserved" % (error.message, error.add) self.message.write (message, "end of program", error.colour) except vpuError, error: self.listener.set_message (error.message, "end of program", error.colour) except: message = "Error: %s, %s" % (sys.exc_type, sys.exc_value) self.listener.set_message (message, "end of program error", "red") else: if step != -1: step += 1 if step == steps_nb: self.listener.set_message ("Next Step", "running", "white") break if honor_breakpoint and self._is_on_breakpoint(): self.listener.set_message ("Continue Program", "at break point", "white") break continue break # vpu.mem_changed set while stepping; similar procedure for registers for i in xrange (self.vpu.nreg): if self.vpu.reg[i] != self.vpu.last_reg[i]: self.vpu.reg_changed.append (i) self.sync() def _is_on_breakpoint (self): try: line = self.vpu.lines [self.vpu.PC] try: i = self.vpu.lines.index (line) except ValueError: return False try: b = self.vpu.BreakP.index (i) except ValueError: return False return True except IndexError: return False # graphical-dependent instructions def output_inst (self, value = '\n', convert_ascii = False): if convert_ascii: value = ("%c" % value).decode() # TODO: validate the string to see whether it is representable buffer = self.output_buffer buffer.insert (buffer.get_end_iter(), "%s" % value) def input_inst (self): dialog = gtk.Dialog ("Insert Input", self.listener.get_toplevel(), gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) dialog.set_has_separator (False) dialog.set_default_response (gtk.RESPONSE_ACCEPT) label = gtk.Label ("Input:") entry = DigitEntry (True, 0) entry.set_activates_default (True) box = gtk.HBox (False, 6) box.set_border_width (6) box.pack_start (label, expand = False) box.pack_start (entry, expand = True) box.show_all() dialog.vbox.pack_start (box) while dialog.run() != gtk.RESPONSE_ACCEPT: pass # force user to accept value = entry.get_value() dialog.destroy() return int (value) ## The view class Interface (gtk.VBox, VpuModel.Listener): def __init__ (self, filename): gtk.VBox.__init__ (self) self.main_parent = None self.vpu = VpuModel (self) # Editor (the text view) self.editor = Editor (self) editor_window = gtk.ScrolledWindow() editor_window.add (self.editor) editor_window.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) editor_window.set_shadow_type (gtk.SHADOW_IN) # the vpu/editor "status bar" statusbar = gtk.HBox (False, 6) if gtk.pygtk_version >= (2,10,0): # gtk 2.10.0 has introduced a nice way to follow the cursor... self.editor_status = gtk.Label ("") self.editor_status.set_alignment (0.0, 0.5) self.editor.get_buffer().connect ("notify::cursor-position", self.cursor_moved_cb) statusbar.pack_start (self.editor_status, True) self.vpu_status = gtk.Label ("ready") self.vpu_status.set_alignment (1.0, 0.5) statusbar.pack_start (self.vpu_status, True) if not test_mode: editor_unlock_button = gtk.Button ("_Edit") # to unlock the editor editor_unlock_button.connect ("clicked", self.edit_button_cb) editor_unlock_button.set_size_request (80, -1) statusbar.pack_start (editor_unlock_button, False) editor_box = gtk.VBox (False, 0) editor_box.pack_start (editor_window, expand = True) editor_box.pack_start (statusbar, expand = False) #editor_box.pack_start (gtk.HSeparator(), expand = False, padding = 2) # Buttons buttons_box = gtk.VBox (True, 0) self.load_button = gtk.Button ("_Load") self.run_button = gtk.Button ("_Run") self.step_button = ButtonWithSpin ("_Step") self.continue_button = gtk.Button ("_Continue") self.clear_button = gtk.Button ("Cle_ar") self.load_button.connect ("clicked", self.load_button_cb) self.run_button.connect ("clicked", self.run_button_cb) self.step_button.connect ("clicked", self.step_button_cb) self.continue_button.connect ("clicked", self.continue_button_cb) self.clear_button.connect ("clicked", self.clear_button_cb) buttons_box.pack_start (self.load_button) buttons_box.pack_start (self.run_button) buttons_box.pack_start (self.step_button) buttons_box.pack_start (self.continue_button) buttons_box.pack_start (self.clear_button) # Informative entries (Program counter & timer) self.counter, counter_box = self.create_informative ("_Program Counter") self.timer, timer_box = self.create_informative ("_Timer") self.counter.modify_text (gtk.STATE_NORMAL, gtk.gdk.Color (0, 0, 65500)) informative_box = gtk.HBox (False, 12) informative_box.pack_start (gtk.Label(), expand = True) informative_box.pack_start (counter_box, expand = False) informative_box.pack_start (timer_box, expand = False) informative_box.pack_start (gtk.Label(), expand = True) # Output text self.output = gtk.TextView() set_monospace_font (self.editor) self.output.set_editable (False) self.output.set_cursor_visible (False) self.output.set_size_request (40, -1) output_win = gtk.ScrolledWindow() output_win.add (self.output) output_win.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) output_win.set_shadow_type (gtk.SHADOW_IN) label = gtk.Label ("_Output") label.set_use_markup (True) label.set_use_underline (True) label.set_mnemonic_widget (self.output) output_box = gtk.VBox (False, 4) output_box.pack_start (label, expand = False) output_box.pack_start (output_win, expand = True) # Registers table self.registers, registers_win, registers_box = self.create_list ("Re_gisters") self.registers.set_search_column (VpuModel.RegModel.INDEX_COL) renderer = gtk.CellRendererText() renderer.set_property ("cell-background-gdk", gtk.gdk.Color(255<<8, 255<<8, 255<<8)) column = gtk.TreeViewColumn ("", renderer, text = VpuModel.RegModel.LABEL_COL, foreground = VpuModel.RegModel.COLOR_COL) column.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED) layout = pango.Layout (self.registers.get_pango_context()) layout.set_text ("RS") width, _ = layout.get_pixel_size() column.set_fixed_width (width+8) column.set_expand (False) renderer = gtk.CellRendererText() renderer.set_property ("cell-background-gdk", gtk.gdk.Color(255<<8, 255<<8, 255<<8)) self.registers.append_column (column) column = gtk.TreeViewColumn ("", renderer, text = VpuModel.RegModel.INDEX_COL, foreground = VpuModel.RegModel.COLOR_COL) column.set_expand (True) column.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED) self.registers.append_column (column) renderer = gtk.CellRendererText() renderer.set_property ("cell-background-gdk", gtk.gdk.Color(255<<8, 255<<8, 255<<8)) column = gtk.TreeViewColumn ("", renderer, text = VpuModel.RegModel.VALUE_COL, foreground = VpuModel.RegModel.COLOR_COL) column.set_expand (True) column.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED) self.registers.append_column (column) # A memory box will be created to allow for easy replacement self.memory_box = gtk.EventBox() self.create_memory_table() # Message label self.message = MessageLabel() # so we can set a border to it message_box = gtk.EventBox() message_box.add (self.message) message_box.set_border_width (6) # Layout editor_buttons_box = gtk.HBox (False, 12) editor_buttons_box.pack_start (editor_box, expand = True) editor_buttons_box.pack_start (buttons_box, expand = False) editor_buttons_box.set_border_width (6) lists_box = RatioHBox (12) lists_box.pack (output_box, 1) lists_box.pack (registers_box, 1) lists_box.pack (self.memory_box, 2) informations_box = gtk.VBox (False, 12) informations_box.pack_start (informative_box, expand = False) informations_box.pack_start (lists_box, expand = True) informations_box.set_border_width (6) self.editor_lists_pane = gtk.VPaned() self.editor_lists_pane.pack1 (editor_buttons_box, True, False) self.editor_lists_pane.pack2 (informations_box, True, False) self.editor_lists_pane.connect ("size-allocate", self.pane_size_allocate_cb, None) self.first_allocate = True # main_box usage is to have a border around the widgets self.pack_start (self.editor_lists_pane, expand = True) self.pack_start (message_box, expand = False) self.file_read (filename) self.vpu.clear() self.show_all() def pane_size_allocate_cb (self, widget, alloc, _data): # we can't set ratios on the pane sides, so we tune it at first allocate if self.first_allocate: self.first_allocate = False pos = int (alloc.height * 0.60) self.editor_lists_pane.set_position (pos) self.editor.grab_focus() # is realized by now ## Functions to cut down on code size def create_list (self, title): list = gtk.TreeView() list.set_headers_visible (False) list.get_selection().set_mode (gtk.SELECTION_NONE) if gtk.pygtk_version >= (2,10,0): list.set_grid_lines (gtk.TREE_VIEW_GRID_LINES_BOTH) list.set_rules_hint (True) list.set_fixed_height_mode (True) window = gtk.ScrolledWindow() window.set_shadow_type (gtk.SHADOW_IN) window.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) window.add (list) if title != None: label = gtk.Label ("" + title + "") label.set_use_markup (True) label.set_use_underline (True) label.set_mnemonic_widget (list) box = gtk.VBox (False, 4) box.pack_start (label, expand = False) box.pack_start (window, expand = True) return (list, window, box) else: return (list, window) def create_memory_table (self): if self.memory_box.child != None: self.memory_box.remove (self.memory_box.child) memory, memory_win = self.create_list (None) self.memory = [memory] self.init_memory_table (memory, True, mirror_memory != "hor") label = gtk.Label ("Memory Data") label.set_use_markup (True) label.set_use_underline (True) label.set_mnemonic_widget (memory) hbox = gtk.HBox (False, 12) hbox.pack_start (memory_win, expand = True) child = vbox = gtk.VBox (False, 4) vbox.pack_start (label, expand = False) vbox.pack_start (hbox, expand = True) if mirror_memory != "no": memory2, memory2_win = self.create_list (None) self.memory += [memory2] self.init_memory_table (memory2, mirror_memory == "ver", True) if mirror_memory == "hor": hbox.pack_start (memory2_win) else: vbox.pack_start (memory2_win) child.show_all() self.memory_box.add (child) def init_memory_table (self, memory, show_label, show_pointer): memory.set_model (self.vpu.ram_model) memory.set_headers_visible (True) if show_label: cell = gtk.CellRendererText() column = gtk.TreeViewColumn ("Label", cell, text = VpuModel.RamModel.LABEL_COL, foreground = VpuModel.RamModel.LABEL_COLOR_COL, cell_background_gdk = VpuModel.RamModel.BACKGROUND_COLOR_COL) column.set_expand (True) column.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED) memory.append_column (column) cell = gtk.CellRendererText() column = gtk.TreeViewColumn ("Address", cell, text = VpuModel.RamModel.INDEX_COL, foreground = VpuModel.RamModel.INDEX_COLOR_COL, cell_background_gdk = VpuModel.RamModel.BACKGROUND_COLOR_COL) column.set_expand (True) column.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED) memory.append_column (column) memory.set_search_column (VpuModel.RamModel.INDEX_COL) cell = gtk.CellRendererText() column = gtk.TreeViewColumn ("Contents", cell, text = VpuModel.RamModel.VALUE_COL, foreground = VpuModel.RamModel.VALUE_COLOR_COL, cell_background_gdk = VpuModel.RamModel.BACKGROUND_COLOR_COL) column.set_expand (True) column.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED) memory.append_column (column) if show_pointer: cell = CellRendererStackPointer() _, _, w, h = cell.do_get_size (memory, None) cell.set_fixed_size (w, h) column = gtk.TreeViewColumn ("", cell, pointer = VpuModel.RamModel.REGS_POINTER_COL, cell_background_gdk = VpuModel.RamModel.BACKGROUND_COLOR_COL) column.set_fixed_width (w) column.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED) column.set_expand (False) memory.append_column (column) def create_informative (self, title): entry = gtk.Entry() entry.set_editable (False) # let's make people see the entry is un-editable... entry.modify_base (gtk.STATE_NORMAL, entry.style.base [gtk.STATE_INSENSITIVE]); entry.set_size_request (40, -1) label = gtk.Label ("" + title + ":") label.set_use_markup (True) label.set_use_underline (True) label.set_mnemonic_widget (entry) box = gtk.HBox (False, 4) box.pack_start (label, expand = False) box.pack_start (entry, expand = False) return (entry, box) ## Interface methods def set_editable (self, editable): self.message.write ("", "white") if editable: self.vpu.clear() self.set_vpu_status ("editing") if gtk.pygtk_version >= (2,10,0): self.cursor_moved_cb (self.editor.get_buffer(), 0) else: self.vpu.load() if gtk.pygtk_version >= (2,10,0): self.editor_status.set_text ("") self.editor.mode.set_mode (self.vpu.vpu) self.run_button.set_sensitive (not editable) self.step_button.set_sensitive (not editable) self.continue_button.set_sensitive (not editable) self.clear_button.set_sensitive (not editable) if self.main_parent != None: self.main_parent.load_menu_sensitive() def get_editable (self): return self.editor.get_editable() def set_vpu_status (self, vpu_status): self.vpu_status.set_text ("Status: " + vpu_status) ## VPU bridge # cuts text into a list of instructions, like [(1, ["x", "rtn", "R2"]), ...] def get_program_code (self): buffer = self.editor.get_buffer() program = [] line = 0 while line < buffer.get_line_count(): splits = buffer.split_line (line) line += 1 if splits == None: break if len (splits) == 0: continue word = splits[0].word if splits[0].word[0] == '#': continue linep = [] if word[-1] == ':': linep.append (word[:-1]) else: linep.append ([]) linep.append (word) for i in xrange (1, len (splits)): word = splits[i].word if word[0] == '#': break else: linep.append (word) program.append ((line, linep)) return program def set_ram_model (self, model): for i in self.memory: i.set_model (model) def set_reg_model (self, model): self.registers.set_model (model) def set_ram_scroll (self, path): self.memory[-1].scroll_to_cell (path) def set_reg_scroll (self, path): self.registers.scroll_to_cell (path) def set_output_buffer (self, buffer): if buffer == None: buffer = gtk.TextBuffer() self.output.set_buffer (buffer) def set_program_counter (self, value): self.counter.set_text (str (value)) # set current line to the VPU one try: line = self.vpu.vpu.lines [value] except: pass else: self.editor.mode.set_current_line (line) def set_timer_counter (self, value): self.timer.set_text (str (value)) def set_message (self, text, status, color, line = -1): self.message.write (text, color) self.set_vpu_status (status) self.editor.mode.set_current_line_color (color) self.editor.mode.set_current_line (line) # interface callbacks def edit_button_cb (self, button): self.set_editable (True) self.editor.grab_focus() def load_button_cb (self, button): self.set_editable (False) def run_button_cb (self, button): self.vpu.advance (-1, False) def step_button_cb (self, button): self.vpu.advance (button.get_value(), False) def continue_button_cb (self, button): self.vpu.advance (-1, True) def clear_button_cb (self, button): self.editor.breakpoints = [] self.editor.queue_draw() self.vpu.BreakP = [] self.message.write ("All break points removed", "white") def cursor_moved_cb (self, buffer, pos_ptr): # for gtk >= 2.10 if self.get_editable(): iter = buffer.get_insert_iter() col = iter.get_line_offset() + 1 lin = iter.get_line() + 1 status = "Ln %d, Col %d" % (lin, col) self.editor_status.set_text (status) # file orders -- from menu def file_read (self, filename): self.set_editable (not test_mode) if filename == None: buffer = self.editor.get_buffer() buffer.delete (buffer.get_start_iter(), buffer.get_end_iter()) else: if not self.editor.get_buffer().read (filename): msg = "Couldn't read from file: " + filename dialog = gtk.MessageDialog (self.get_toplevel(), gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg) dialog.run() dialog.destroy() filename = None if test_mode: sys.exit (2) self.filename = filename return False def file_save (self, filename): if self.editor.get_buffer().write (filename): self.filename = filename else: msg = "Couldn't save to file: " + filename dialog = gtk.MessageDialog (self.get_toplevel(), gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg) dialog.format_secondary_text ("Check file permissions") dialog.run() dialog.destroy() def file_print (self): self.editor.print_text (self.main_parent, self.filename) # edit orders -- from menu def edit_undo (self): if not self.editor.get_editable(): return self.editor.get_buffer().undo() def edit_redo (self): if not self.editor.get_editable(): return self.editor.get_buffer().redo() def edit_can_undo (self): return self.editor.get_buffer().can_undo() def edit_can_redo (self): return self.editor.get_buffer().can_redo() def edit_cut (self): buffer = self.editor.get_buffer() clipboard = gtk.clipboard_get() buffer.cut_clipboard (clipboard, self.editor.get_editable()) def edit_copy (self): buffer = self.editor.get_buffer() clipboard = gtk.clipboard_get() buffer.copy_clipboard (clipboard) def edit_paste (self): if not self.editor.get_editable(): return buffer = self.editor.get_buffer() clipboard = gtk.clipboard_get() buffer.paste_clipboard (clipboard, None, True) def edit_kill_line (self): if not self.editor.get_editable(): return buffer = self.editor.get_buffer() line = buffer.get_iter_at_mark (buffer.get_insert()).get_line() start_it = buffer.get_iter_at_line (line) end_it = start_it.copy() end_it.forward_line() clipboard = gtk.clipboard_get() clipboard.set_text (buffer.get_text (start_it, end_it, False)) buffer.delete (start_it, end_it) def edit_yank (self): self.edit_paste_cb (item) def edit_mark_region (self): if not self.editor.get_editable(): return buffer = self.editor.get_buffer() it = buffer.get_iter_at_mark (buffer.get_insert()) mark = buffer.get_mark ("emacs-mark") if mark: buffer.move_mark (mark, it) else: buffer.create_mark ("emacs-mark", it, True) def edit_kill_region (self): if not self.editor.get_editable(): return buffer = self.editor.get_buffer() buffer.delete_selection (True) def edit_copy_region_as_kill (self): self.edit_cut_cb (item) def edit_line_home (self): buffer = self.editor.get_buffer() it = buffer.get_iter_at_mark (buffer.get_insert()) it.set_line_offset(0) buffer.place_cursor (it) def edit_line_end (self): buffer = self.editor.get_buffer() it = buffer.get_iter_at_mark (buffer.get_insert()) it.forward_to_line_end() buffer.place_cursor (it) def edit_buffer_home (self): buffer = self.editor.get_buffer() it = buffer.get_start_iter() buffer.place_cursor (it) def edit_buffer_end (self): buffer = self.editor.get_buffer() it = buffer.get_end_iter() buffer.place_cursor (it) def edit_delete_right_char (self): if not self.editor.get_editable(): return buffer = self.editor.get_buffer() start_it = buffer.get_iter_at_mark (buffer.get_insert()) end_it = start_it.copy() if end_it.forward_char(): buffer.delete (start_it, end_it) gobject.type_register (Interface) # used as a ref to keep gtk loop alive until there are still windows open, and # also to apply settings changes to all windows. windows = [] class Window (gtk.Window): def __init__ (self, filenames = [], interface = None): gtk.Window.__init__ (self) if test_mode: self.set_title ("Apoo Tester") else: self.set_title ("Apoo Workbench") self.set_default_size (460, 550) self.connect ("delete-event", self.ask_close_window_cb) self.connect ("destroy", self.close_window_cb) self.menu = gtk.MenuBar() # needed for the menu key shortcuts self.accel_group = gtk.AccelGroup() self.add_accel_group (self.accel_group) self.load_menu() self.notebook = gtk.Notebook() self.notebook.set_group_id (0) self.notebook.set_scrollable (True) self.notebook.connect ("page-added", self.notebook_page_added_cb) self.notebook.connect_after ("page-removed", self.notebook_page_changed_cb) self.notebook.connect_after ("switch-page", self.notebook_page_changed_cb) self.notebook_popup = gtk.Menu() item = gtk.MenuItem ("Move to New Window") item.connect ("activate", self.notebook_detach_child_cb) item.show() self.notebook_popup.append (item) self.notebook_popup.attach_to_widget (self.notebook, None) self.notebook.connect ("button-press-event", self.notebook_button_press_cb) box = gtk.VBox (False, 0) box.pack_start (self.menu, expand = False) box.pack_start (self.notebook, expand = True) self.add (box) for i in filenames: self.open_file (i) if interface != None: self.add_child (interface) elif len (filenames) == 0: self.add_child (Interface (None)) self.show_all() global windows windows.append (self) ## Interface handling def get_child (self): return self.notebook.get_nth_page (self.notebook.get_current_page()) def add_child (self, child): label = gtk.HBox (False, 0) # close button based on GEdit -- make it small close_image = gtk.Image() close_image.set_from_stock (gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) close_button = gtk.Button() close_button.add (close_image) close_button.set_relief (gtk.RELIEF_NONE) close_button.set_focus_on_click (False) gtk.rc_parse_string ( "style \"zero-thickness\"\n" + "{\n" + " xthickness = 0\n" + " ythickness = 0\n" + "}\n" + "widget \"*.pagebutton\" style \"zero-thickness\"" ) close_button.set_name ("pagebutton") if gtk.pygtk_version >= (2,12,0): close_button.set_tooltip_text ("Close document") close_button.connect ("clicked", self.notebook_page_close_cb, child) close_button.connect ("style-set", self.notebook_close_button_style_set_cb) label.label = gtk.Label ("") label.pack_start (label.label, True) label.pack_start (close_button, False) label.show_all() page_num = self.notebook.append_page (child, label) self.notebook.set_current_page (page_num) self.load_child_title (child) if gtk.pygtk_version >= (2,10,0): self.notebook.set_tab_reorderable (child, True) self.notebook.set_tab_detachable (child, True) child.editor.get_buffer().connect ("modified-changed", self.child_edited_cb, child) def close_child (self, child): self.notebook.remove_page (self.notebook.page_num (child)) def open_file (self, filename): # None for empty if filename != None: # close page if it is blank pages = self.notebook.get_children() if len (pages) > 0: page = pages [len (pages)-1] if page.filename == None and not page.editor.get_buffer().get_modified(): self.close_child (page) self.add_child (Interface (filename)) self.file_accessed (filename) def save_file (self, ask, child = None): if child == None: child = self.get_child() filename = child.filename if filename == None: ask = True if ask: global default_dir dialog = gtk.FileChooserDialog ("Save File", self, gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) if default_dir != None: dialog.set_current_folder (default_dir) filter = gtk.FileFilter() filter.set_name ("Apoo programs") filter.add_pattern ("*.apoo") dialog.set_filter (filter) dialog.set_default_response (gtk.RESPONSE_ACCEPT) ret = dialog.run() if ret == gtk.RESPONSE_ACCEPT: default_dir = dialog.get_current_folder() filename = dialog.get_filename() if not filename.endswith (".apoo"): filename += ".apoo" dialog.destroy() else: dialog.destroy() return False child.file_save (filename) self.file_accessed (filename) if ask: self.load_child_title (child) return True def file_accessed (self, filename): if gtk.pygtk_version >= (2,10,0): manager = gtk.recent_manager_get_default() data = { 'mime_type': "text/plain", 'app_name': "apoo", 'app_exec': "apoo", 'display_name': os.path.basename (filename), 'groups': ['apoo'], 'is_private': bool (False), 'description': "Apoo program" } uri = filename if filename[0] != '/': uri = os.path.join (os.getcwd(), filename) uri = "file:/" + uri manager.add_full (uri, data) def load_child_title (self, child): if child.filename == None: title = "(unnamed)" else: title = os.path.basename (child.filename) if child.editor.get_buffer().get_modified(): title = "" + title + "" label = self.notebook.get_tab_label (child) label.label.set_markup (title) ## Events callbacks def notebook_page_added_cb (self, notebook, child, page_num): child.main_parent = self self.load_menu_sensitive() def notebook_page_changed_cb (self, notebook, page_ptr, page_num): # either removed or just a switch self.load_menu_sensitive() def notebook_page_close_cb (self, button, child): if self.confirm_child_changes (child): self.close_child (child) def notebook_close_button_style_set_cb (self, button, prev_style): w, h = gtk.icon_size_lookup_for_settings (button.get_settings(), gtk.ICON_SIZE_MENU) button.set_size_request (w+2, h+2) def notebook_get_page_at (self, x, y): # utility for press button page_num = 0 while (page_num < self.notebook.get_n_pages()): page = self.notebook.get_nth_page (page_num) label = self.notebook.get_tab_label (page) if label.window.is_visible(): label_x, label_y = label.window.get_origin() alloc = label.get_allocation() label_x += alloc.x label_y += alloc.y if x >= label_x and x <= label_x+alloc.width and y >= label_y and y <= label_y+alloc.height: return (page_num, page) page_num += 1 return (-1, None) def notebook_button_press_cb (self, notebook, event): if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: page_num, _ = self.notebook_get_page_at (event.x_root, event.y_root) if page_num != -1: self.notebook.set_current_page (page_num) self.notebook_popup.popup (None, None, None, 3, event.time) return False def notebook_detach_child_cb (self, item): child = self.get_child() self.close_child (child) Window (interface = child) def child_edited_cb (self, buffer, child): self.load_child_title (child) def file_new_cb (self, item): self.open_file (None) def file_open_cb (self, item): dialog = gtk.FileChooserDialog ("Open File", self, gtk.FILE_CHOOSER_ACTION_OPEN, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT)) global default_dir if default_dir != None: dialog.set_current_folder (default_dir) filter = gtk.FileFilter() filter.set_name ("Apoo programs") filter.add_pattern ("*.apoo") dialog.set_filter (filter) dialog.set_select_multiple (True) dialog.set_default_response (gtk.RESPONSE_ACCEPT) if dialog.run() == gtk.RESPONSE_ACCEPT: default_dir = dialog.get_current_folder() for i in dialog.get_filenames(): self.open_file (i) dialog.destroy() def file_open_recent_cb (self, chooser): uri = chooser.get_current_uri() if len (uri) > 6 and uri[0:6] == "file:/": uri = uri[6:] self.open_file (uri) def file_save_cb (self, item): self.save_file (False) def file_save_as_cb (self, item): self.save_file (True) def file_print_cb (self, item): self.get_child().file_print() def file_close_cb (self, item): child = self.get_child() if self.confirm_child_changes (child): self.close_child (child) def file_quit_cb (self, item): if self.confirm_changes(): self.destroy() def edit_undo_cb (self, item): self.get_child().edit_undo() def edit_redo_cb (self, item): self.get_child().edit_redo() def edit_cut_cb (self, item): self.get_child().edit_cut() def edit_copy_cb (self, item): self.get_child().edit_copy() def edit_paste_cb (self, item): self.get_child().edit_paste() def edit_kill_line_cb (self, item): self.get_child().edit_kill_line() def edit_yank_cb (self, item): self.get_child().edit_yank() def edit_mark_region_cb (self, item): self.get_child().edit_mark_region() def edit_kill_region_cb (self, item): self.get_child().edit_kill_region() def edit_copy_region_as_kill_cb (self, item): self.get_child().edit_copy_region_as_kill() def edit_buffer_home_cb (self, item): self.get_child().edit_buffer_home() def edit_buffer_end_cb (self, item): self.get_child().edit_buffer_end() def edit_line_home_cb (self, item): self.get_child().edit_line_home() def edit_line_end_cb (self, item): self.get_child().edit_line_end() def edit_delete_right_char_cb (self, item): self.get_child().edit_delete_right_char() def edit_preferences_cb (self, item): preferences_show (self) def show_file_text_dialog (self, title, path,filename): dialog = gtk.Dialog (title, self, buttons = (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) dialog.set_default_response (gtk.RESPONSE_CLOSE) dialog.connect ("response", self.close_file_text_dialog_cb) dialog.set_default_size (-1, 450) buffer = gtk.TextBuffer() file = open (path+filename + ".txt", 'r') buffer.set_text (file.read()) file.close() view = gtk.TextView (buffer) view.set_editable (False) view.set_cursor_visible (False) set_monospace_font (view) window = gtk.ScrolledWindow() window.set_policy (gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) window.set_shadow_type (gtk.SHADOW_IN) window.add (view) dialog.vbox.pack_start (window, True) dialog.show_all() # not run() because we don't want it modal def close_file_text_dialog_cb (self, dialog, response): dialog.destroy() def help_interface_cb (self, item): if test_mode: doc = DOC_TESTER else: doc = DOC_APOO self.show_file_text_dialog ("Help on the Apoo Interface", DOCS_PATH,doc) def help_language_cb (self, item): self.show_file_text_dialog("Help on the Apoo Assembly Language", DOCS_PATH,DOC_ASSEMBLY) def help_about_cb (self, item): dialog = gtk.AboutDialog() dialog.set_transient_for (self) dialog.set_name ("Apoo") dialog.set_version (VERSION) dialog.set_copyright("Licensed under the GNU General Public License") dialog.set_website ("http://www.ncc.up.pt/apoo") dialog.set_authors (["Rogerio Reis ", "Nelma Moreira ", "(Apoo main developers)", "", "Ricardo Cruz ", "(interface developer)"]) dialog.run() dialog.destroy() def run_confirm_dialog (self, nb, content): if nb > 1: msg = "There are " + str (nb) + " documents unsaved.\n" else: msg = "Document modified. " msg += "Save changes?" dialog = gtk.MessageDialog (self, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE, msg) dialog.add_button ("Don't Save", gtk.RESPONSE_REJECT) dialog.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) dialog.add_button (gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT) if content != None: dialog.vbox.pack_start (content) content.show_all() ret = dialog.run() dialog.destroy() return ret def confirm_child_changes (self, child): if not child.editor.get_buffer().get_modified(): return True response = self.run_confirm_dialog (1, None) if response == gtk.RESPONSE_CANCEL: return False if response == gtk.RESPONSE_ACCEPT: return self.save_file (False, child) return True def confirm_changes (self): model = gtk.ListStore (bool, str, int) editors = self.notebook.get_children() modified = 0 for i in xrange (len (editors)): if editors[i].editor.get_buffer().get_modified(): iter = model.append() name = editors[i].filename if name == None: name = "(page " + str (self.notebook.page_num (editors[i])+1) + ")" model.set (iter, 0, True, 1, name, 2, i) modified += 1 if modified == 0: return True view = gtk.TreeView (model) view.set_headers_visible (False) view.get_selection().set_mode (gtk.SELECTION_NONE) view.set_search_column (1) renderer = gtk.CellRendererToggle() renderer.connect ("toggled", self.confirm_filename_toggled_cb, model) view.connect ("row-activated", self.confirm_filename_activated_cb, model) column = gtk.TreeViewColumn ("", renderer, active = 0) view.append_column (column) column = gtk.TreeViewColumn ("Filename", gtk.CellRendererText(), text = 1) view.append_column (column) scroll = gtk.ScrolledWindow() scroll.set_policy (gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) scroll.set_shadow_type (gtk.SHADOW_OUT) scroll.set_size_request (-1, 80) scroll.add (view) response = self.run_confirm_dialog (modified, scroll) if response == gtk.RESPONSE_ACCEPT: iter = model.get_iter_first() while iter != None: value = model.get_value (iter, 0) if value: i = model.get_value (iter, 2) if not self.save_file (False, editors[i]): return False iter = model.iter_next (iter) return True return response == gtk.RESPONSE_REJECT def confirm_filename_toggle (self, model, iter): value = model.get_value (iter, 0) model.set (iter, 0, not value) def confirm_filename_toggled_cb (self, cell, path_str, model): iter = model.get_iter_from_string (path_str) self.confirm_filename_toggle (model, iter) def confirm_filename_activated_cb (self, view, path, col, model): iter = model.get_iter (path) self.confirm_filename_toggle (model, iter) def ask_close_window_cb (self, window, event): if self.confirm_changes(): return False else: return True def close_window_cb (self, window): global windows windows.remove (self) if len (windows) == 0: gtk.main_quit() return False ## Menu builder def load_menu_sensitive (self): pages_nb = self.notebook.get_n_pages() editing = False if pages_nb > 0: editing = self.get_child().get_editable() for i in self.menu_page_items: i.set_sensitive (pages_nb > 0) for i in self.menu_edit_items: i.set_sensitive (editing) def load_menu (self): # remove any current entries for i in self.menu.get_children(): self.menu.remove (i) self.menu_page_items = [] self.menu_edit_items = [] file_menu = gtk.Menu() item = self.add_menu_item (self.menu, "_File") item.set_submenu (file_menu) if not test_mode: self.add_menu_item (file_menu, "_New", gtk.STOCK_NEW, self.file_new_cb) self.add_menu_item (file_menu, "_Open", gtk.STOCK_OPEN, self.file_open_cb) if gtk.pygtk_version >= (2,10,0): manager = gtk.recent_manager_get_default() recents_menu = gtk.RecentChooserMenu (manager) recents_menu.set_show_numbers (True) recents_menu.set_local_only (True) recents_menu.set_sort_type (gtk.RECENT_SORT_MRU) recents_menu.set_limit (10) filter = gtk.RecentFilter() filter.add_pattern ("*.apoo") recents_menu.set_filter (filter) item = self.add_menu_item (file_menu, "Open _Recent") item.set_submenu (recents_menu) recents_menu.connect ("item-activated", self.file_open_recent_cb) self.add_menu_item (file_menu, "-") self.add_menu_item (file_menu, "_Save", gtk.STOCK_SAVE, self.file_save_cb, group = self.menu_page_items) self.add_menu_item (file_menu, "Save _As", gtk.STOCK_SAVE_AS, self.file_save_as_cb, group = self.menu_page_items) self.add_menu_item (file_menu, "-") if gtk.pygtk_version >= (2,10,0): self.add_menu_item (file_menu, "_Print", gtk.STOCK_PRINT, self.file_print_cb, (gtk.gdk.CONTROL_MASK, ord ('p')), group = self.menu_page_items) self.add_menu_item (file_menu, "-") self.add_menu_item (file_menu, "_Close", gtk.STOCK_CLOSE, self.file_close_cb, group = self.menu_page_items) self.add_menu_item (file_menu, "_Quit", gtk.STOCK_QUIT, self.file_quit_cb) edit_menu = gtk.Menu() item = self.add_menu_item (self.menu, "_Edit") item.set_submenu (edit_menu) if not test_mode: self.add_menu_item (edit_menu, "_Undo", gtk.STOCK_UNDO, self.edit_undo_cb, (gtk.gdk.CONTROL_MASK, ord ('z')), self.menu_edit_items) self.add_menu_item (edit_menu, "_Redo", gtk.STOCK_REDO, self.edit_redo_cb, (gtk.gdk.CONTROL_MASK|gtk.gdk.SHIFT_MASK, ord ('z')), self.menu_edit_items) self.add_menu_item (edit_menu, "-") if shortcuts_style == "emacs": self.add_menu_item (edit_menu, "Kill Line", None, self.edit_kill_line_cb, (gtk.gdk.CONTROL_MASK, ord ('k')), self.menu_edit_items) self.add_menu_item (edit_menu, "Yank", None, self.edit_yank_cb, (gtk.gdk.CONTROL_MASK, ord ('y')), self.menu_edit_items) self.add_menu_item (edit_menu, "-") self.add_menu_item (edit_menu, "Mark Region", None, self.edit_mark_region_cb, (gtk.gdk.CONTROL_MASK, ord (' ')), self.menu_edit_items) # GTK+ doesn't support an accelerator like Esc+W self.add_menu_item (edit_menu, "Copy Region as Kill", None, self.edit_copy_region_as_kill_cb, (gtk.gdk.CONTROL_MASK, 65307), self.menu_edit_items) self.add_menu_item (edit_menu, "Kill Region", None, self.edit_kill_region_cb, (gtk.gdk.CONTROL_MASK, ord ('w')), self.menu_edit_items) self.add_menu_item (edit_menu, "-") self.add_menu_item (edit_menu, "Line Home", None, self.edit_line_home_cb, (gtk.gdk.CONTROL_MASK, ord ('a')), self.menu_edit_items) self.add_menu_item (edit_menu, "Line End", None, self.edit_line_end_cb, (gtk.gdk.CONTROL_MASK, ord ('e')), self.menu_edit_items) self.add_menu_item (edit_menu, "-") self.add_menu_item (edit_menu, "Delete Right Character", None, self.edit_delete_right_char_cb, (gtk.gdk.CONTROL_MASK, ord ('d')), self.menu_edit_items) else: # "desktop" self.add_menu_item (edit_menu, "Cu_t", gtk.STOCK_CUT, self.edit_cut_cb, group = self.menu_edit_items) self.add_menu_item (edit_menu, "_Copy", gtk.STOCK_COPY, self.edit_copy_cb, group = self.menu_page_items) self.add_menu_item (edit_menu, "_Paste", gtk.STOCK_PASTE, self.edit_paste_cb, group = self.menu_edit_items) self.add_menu_item (edit_menu, "-") self.add_menu_item (edit_menu, "_Preferences...", gtk.STOCK_PREFERENCES, self.edit_preferences_cb) help_menu = gtk.Menu() item = self.add_menu_item (self.menu, "_Help") item.set_submenu (help_menu) self.add_menu_item (help_menu, "_Interface Help", gtk.STOCK_HELP, self.help_interface_cb, (0, 0xFFBE)) # F1 self.add_menu_item (help_menu, "_Assembly Help", gtk.STOCK_HELP, self.help_language_cb, (0, 0xFFBF)) # F2 self.add_menu_item (help_menu, "_About", gtk.STOCK_ABOUT, self.help_about_cb) self.menu.show_all() # convience methods to create the menu to cut down on code def add_menu_item (self, parent, label, image = None, callback = None, shortcut = None, group = None): # shortcut = (modified, key) if label == '-': item = gtk.SeparatorMenuItem() else: # we'll create the item widget ourselves since pygtk isn't very nice here box = gtk.HBox (False, 6) glabel = gtk.AccelLabel (label) glabel.set_use_underline (True) glabel.set_alignment (0, 0.5) if image: gimage = gtk.Image() gimage.set_from_stock (image, gtk.ICON_SIZE_MENU) box.pack_start (gimage, False) box.pack_start (glabel, True) item = gtk.MenuItem() item.add (box) glabel.set_accel_widget (item) if shortcut == None and image != None: # set stock image assigned key info = gtk.stock_lookup (image) shortcut = (info[2], info[3]) # some stock icons have bad shortcuts, so do a check... if shortcut[1] <= 0: shortcut = None if shortcut != None: key = shortcut[1] modifier = shortcut[0] item.add_accelerator ("activate", self.accel_group, key, modifier, gtk.ACCEL_VISIBLE) if callback != None: item.connect ("activate", callback) parent.append (item) item.show_all() if group != None: group.append (item) return item if __name__ == "__main__": # parse arguments at first filenames = [] argv = sys.argv for i in xrange (1, len (argv)): if argv[i] == "--tester" or argv[i] == "-t": test_mode = True elif argv[i] == "--help" or argv[i] == "-h": print "Usage: " + argv[0] + " [OPTIONS] [FILENAME]" print "Options may be:" print "\t--tester, -t\tExecute-only mode" print "\t--help, -h\tShow this help text" print "" sys.exit (0) elif argv[i][0] == '-': print "Unrecognized argument: " + argv[i] print "For usage: " + argv[0] + " --help" sys.exit (1) else: filenames.append (argv[i]) if test_mode and len (filenames) == 0: print "Usage: " + argv[0] + " --tester filename" sys.exit (1) # go on, now read_config() Window (filenames) gtk.main() write_config() apoo-2.2/subst.py0000750000076600000240000000046510745416725013076 0ustar rvrdialout#!/usr/bin/python from sys import __stdin__, __stdout__, argv import sys, string if len(argv) != 3: print "Usage: subst.py str1 str2" print " substitutes str1 with str2 in te stdin." sys.exit(1) for line in __stdin__.readlines(): line = string.replace(line,argv[1],argv[2]) print line, apoo-2.2/vpu.py0000640000076600000240000004705510745416725012554 0ustar rvrdialout#!/usr/bin/python # -*- coding: utf-8 -*- """ Apoo Virtual Processor Copyright (C) 1998-2006 Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @author: Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt """ from constants import * import string, sys, time, copy __version = "3.0p2" Changed = (None,None) class Vpu: def __init__(self, n=8, MpMem={}, Inter=None, RAMSize=1000): """This is where all the pseudo-code is specified. Any new intruction added shoud be added to the constants.py module too, where the lexical information resides. @arg n: is the number of registers to support.""" self.reg = [] self.nreg = n for i in range(n): self.reg.append(0) self.RAM = [] self.Prog = [] self.labelp = {} self.labelm = {} self.labelms = {} self.constants = {} self.PC = 0 self.SPn = n-1 self.FPn = n-2 self.BreakP = [] self.StaticMem = 0 self.lines = [] self.time0, self.time = 0,0 self.Inter=Inter self.RAMSize = RAMSize self.MpMem = copy.deepcopy(MpMem) self.code = {'add':("Reg[A2] = Reg[A2] + Reg[A1]", "incPC()"), 'and':("Reg[A2] = Reg[A1] & Reg[A2]", "incPC()"), 'dec':("Reg[A1] = Reg[A1] - 1", "incPC()"), 'div':("Reg[A2] = Reg[A1] / Reg[A2]", "incPC()"), 'halt':("raise EndOfProgram"), 'inc':("Reg[A1] = Reg[A1] + 1", "incPC()"), 'jneg':("if Reg[A1] < 0:", " if type(A2) == type(''):", " add = self.ParseLabelP(A2)", " else: add = A2", " self.PC = add", "else: self.PC = self.PC + 1"), 'jpos':("if Reg[A1] > 0:", " if type(A2) == type(''):", " add = self.ParseLabelP(A2)", " else: add = A2", " self.PC = add", "else: self.PC = self.PC + 1"), 'jsr':("if type(A1) == type(''):", " add = self.ParseLabelP(A1)", "else: add = A1", "self.push(self.PC + 1)", "self.PC = add"), 'jump':("if type(A1) == type(''):", " try: add = self.labelp[A1]", " except KeyError: raise LabelError", "else: add = A1", "self.PC = add"), 'jumpi':("self.PC = Reg[A1]"), 'jnzero':("if Reg[A1] != 0:", " if type(A2) == type(''):", " add = self.ParseLabelP(A2)", " else: add = i[2]", " self.PC = add", "else: self.PC = self.PC + 1"), 'jzero':("if Reg[A1] == 0:", " if type(A2) == type(''):", " add = self.ParseLabelP(A2)", " else: add = i[2]", " self.PC = add", "else: self.PC = self.PC + 1"), 'load':("if type(A1) == type(''):", " try: add = self.labelm[A1]", " except KeyError: raise LabelError", "else: add = A1", "try: foo = self.MLoad(add)", "except IndexError: raise OutOfMemory(add)", "Reg[A2] = foo", "incPC()"), 'loadi':("add = Reg[A1]", "try: foo = self.MLoad(add)", "except IndexError: raise OutOfMemory(add)", "Reg[A2] = foo", "incPC()"), 'loadn':("if type(A1) == type(''):", " v = self.ParseLabel(A1)", "else: v = A1", "Reg[A2] = v", "incPC()"), 'loado':("add = Reg[self.FPn]+A1", "try: foo = self.MLoad(add)", "except IndexError: raise OutOfMemory(add)", "Reg[A2] = foo", "incPC()"), 'mod':("Reg[A2] = Reg[A1] % Reg[A2]", "incPC()"), 'mul':("Reg[A2] = Reg[A1] * Reg[A2]", "incPC()"), 'or':("Reg[A2] = Reg[A1] | Reg[A2]", "incPC)"), 'pop':("Reg[A1] = self.pop()", "incPC()"), 'push':("self.push(Reg[A1])", "incPC()"), 'rtn':("self.PC = self.pop()"), 'store':("if type(A2) == type (''):", " try: add = self.labelm[A2]", " except KeyError: raise LabelError", "else: add = A2", "foo = Reg[A1]", "try: self.MStore(add,foo)", "except IndexError: raise OutOfMemory(add)", "incPC()"), 'storei':("try: self.MStore(Reg[A2],Reg[A1])", "except IndexError:", " raise OutOfMemory(Reg[A2])", "incPC()"), 'storen':("if type(A1) == type(''):", " r = self.ParseLabel(A1)", "else: r = A1", "Reg[A2]=r", "incPC()"), 'storeo':("add = Reg[self.FPn]+A2", "try:self.MStore(add,Reg[A1])", "except IndexError:", " raise OutOfMemory(add)", "incPC()"), 'storer':("Reg[A2] = Reg[A1]", "incPC()"), 'sub':("Reg[A2] = Reg[A1] - Reg[A2]", "incPC()"), 'xor':("Reg[A2] = Reg[A1] ^ Reg[A2]", "incPC()"), 'nop':("incPC()"), 'zero':("Reg[A1] = 0", "incPC()")} for k in self.code.keys(): self.code[k] = expandCode(self.code[k]) def clean(self): """Ensures all the memory areas are clean.""" for i in range(self.nreg): self.reg[i]=0 self.RAM = [] self.Prog = [] self.labelp = {} self.labelm = {} self.labelms = {} self.PC = 0 self.BreakP = [] self.lines = [] self.time0, self.time = 0,0 def __str__(self): """Only used for debugging purposes.""" return str((self.PC,self.reg,self.reg[self.SPn])) def __repr__(self): """Only used for debugging purposes.""" return 'Vpu( %s )'% self.__str__() def MStore(self,add,val): """Store in memory shell that deals with mapped memory """ global Changed if add in self.MpMem.keys(): exec self.MpMem[add][1] elif self.RAMSize <= add or add < 0: raise OutOfMemory(add) else: self.RAM[add] = val Changed = (add,val) def MLoad(self,add): """Load from RAM shell that deals with mapped memory """ if add in self.MpMem.keys(): val = 0 exec self.MpMem[add][0] return val elif self.RAMSize <= add or add < 0: raise OutOfMemory(add) else: return self.RAM[add] def run(self, MaxSteps=1000): """Starts the execution of the current program. @arg MaxSteps: the maximum allowed number of steps to execute for infinite loop detection.""" i = 0 while True: self.step() if i > MaxSteps: raise TooManySteps(i) else: i = i + 1 def setbreak(self,linum): """Create a breakpoint""" if not linum in self.BreakP: self.BreakP.append(linum) def clearbreak(self,linum): """Clear a breakpoint""" if linum in self.BreakP: del(self.BreakP[self.BreakP.index(linum)]) def cont(self,num): i = 0 while True: self.step() if i > num: raise TooManySteps(num) i = i + 1 if self.PC in self.BreakP: return def step(self): """basic execution of a step of the program""" global Changed Changed=(None,None) self.TimerOn() try: i = self.Prog[self.PC] except IndexError: self.TimerOff() raise OutOfProgram if type(i) == type(''): # no args exec self.code[i] else: exec self.code[i[0]] self.TimerOff() return Changed def incPC(self): self.PC = self.PC + 1 def load(self,program): self.clean() for (n,i) in program: if len(i) < 2: if i[0] == []: raise LabelError(n) else: i.append('nop') if i[1] == 'equ': if len(i) != 3: raise BadArgs(n) if i[0] == []: raise BadArgs(n) else: validateLabelName(i[0],n) if isNumber(i[2]): self.constants[i[0]]= int(i[2]) else: raise BadArgs(n) continue if i[1] == 'const': if len(i) != 3: raise BadArgs(n) if i[0] != []: validateLabelName(i[0],n) self.labelm[i[0]] = len(self.RAM) self.labelms[i[0]] = 1 lastLabel = i[0] else: self.labelms[lastLabel] = self.labelms[lastLabel] + 1 r = charORint(i[2],n) self.RAM.append(r) continue if i[1] == "string": if len(i) != 3: raise BadArgs(n) strarg = validateString(i[2],n) if i[0] != []: validateLabelName(i[0],n) self.labelm[i[0]] = len(self.RAM) self.labelms[i[0]] = len(strarg)+1 for j in strarg: self.RAM.append(ord(j)) self.RAM.append(0) continue if i[1] == 'mem': if len(i) != 3: raise BadArgs(n) try: r = int(i[2]) except ValueError: raise NotInt(n) if i[0] != []: validateLabelName(i[0],n) self.labelm[i[0]] = len(self.RAM) self.labelms[i[0]] = r # this is only for tutor use for foo in range(r): self.RAM.append(0) continue if i[0] != []: validateLabelName(i[0],n) self.labelp[i[0]] = len(self.Prog) self.lines.append(n) if i[1] in inst[0]: # no args if len(i) != 2: raise BadArgs(n) else: self.Prog.append((i[1],)) elif i[1] in inst[1]: # nonreg if len(i) != 3: raise BadArgs(n) else: self.Prog.append((i[1],self.ParseNum(i[2]))) elif i[1] in inst[2]: # reg if len(i) != 3: raise BadArgs(n) r1 = ParseReg(i[2],self.nreg,n) self.Prog.append((i[1],r1)) elif i[1] in inst[3]: # reg reg if len(i) != 4: raise BadArgs(n) r1 = ParseReg(i[2],self.nreg,n) r2 = ParseReg(i[3],self.nreg,n) self.Prog.append((i[1],r1,r2)) elif i[1] in inst[4]: # nonreg reg if len(i) != 4: raise BadArgs(n) r1 = ParseReg(i[3],self.nreg,n) self.Prog.append((i[1],self.ParseNum(i[2]),r1)) elif i[1] in inst[5]: # reg nonreg if len(i) != 4: raise BadArgs(n) r1 = ParseReg(i[2],self.nreg,n) self.Prog.append((i[1],r1,self.ParseNum(i[3]))) else: raise IllInst(n) self.StaticMem = len(self.RAM)-1 self.RAM += [ 0 for i in xrange(self.RAMSize)] self.reg[self.SPn] = self.StaticMem self.reg[self.FPn] = self.reg[self.SPn] + 1 def push(self,val): self.reg[self.SPn] += 1 self.MStore(self.reg[self.SPn],val) def pop(self): if self.reg[self.SPn] <= self.StaticMem: raise MemoryUnderflow(self.reg[self.SPn]) foo = self.MLoad(self.reg[self.SPn]) self.reg[self.SPn] -= 1 return foo def ParseNum(self,st): if st in self.constants.keys(): return self.constants[st] elif st[0] in string.digits or st[0] == '-': return int(st) else: return st def ParseLabel(self,st): try: r = self.labelm[st] except KeyError: raise LabelError return r def ParseLabelP(self,st): try: r = self.labelp[st] except KeyError: raise LabelError return r def destructLabel(self,label): if label in self.labelm.keys(): del(self.labelm[label]) if label in self.labelms.keys(): del(self.labelms[label]) def reserveMemory1(self,label,size): self.destructLabel(label) self.labelm[label] = len(self.RAM) for i in range(size): self.RAM.append(0) self.labelms[label] = size def relocateLabel(self,label,dif): for n in self.labelm.keys(): if self.labelm[n] > self.labelm[label] : self.labelm[n] = self.labelm[n] + dif if dif > 0: for i in range(dif): self.RAM.insert(self.labelm[label],0) if dif < 0: self.RAM[(self.labelm[label]+ self.labelms[label] +dif):(self.labelm[label]+ self.labelms[label])]=[] def reserveMemory(self,label,size): if label in self.labelm.keys(): if self.labelms[label] != size: dif = size - self.labelms[label] self.relocateLabel(label,dif) else: for i in range(size): self.RAM[self.labelm[label]+i] = 0 else: self.labelm[label] = len(self.RAM) for i in range(size): self.RAM.append(0) self.labelms[label] = size def TimerInit(self): self.time = 0 def TimerOn(self): self.time0 = time.clock() def TimerOff(self): self.time = self.time + (time.clock() - self.time0) def ReadProgram(filename): try: input = open(filename, 'r') except IOError: CantRead(filename) program = [] linum = 0 while 1: line = input.readline() linep = [] linum = linum + 1 if not line: break if len(line) == 1: continue line = string.split(line) if line: if line[0][len(line[0])-1] == ':' and line[0][0] != '#': linep.append(line[0][:len(line[0])-1]) elif line[0][0] == '#': continue else: linep.append([]) linep.append(line[0]) for i in range(1,len(line)): if line[i][0] == '#': continue else: linep.append(line[i]) program.append((linum,linep)) return program def CantRead(file): sys.stderr.write("Error: Cannot read file %s\n"%file) sys.exit(1) def ParseReg(st,nreg,line): if st[0] != 'r' and st[0] != 'R': raise IllOperand(line) elif st == "RS" or st == "rs": st = "R%d"%(nreg-1) elif st == "RF" or st == "rf": st = "R%d"%(nreg-2) try: i = int(st[1:len(st)]) except ValueError: raise IllOperand(line) if not i in range(nreg): raise IllReg(line) return i def expandCode(list): if type(list) == type(''): return expandCode1(list) else: s = expandCode1(list[0]) for i in list[1:]: s = s + "\n" + expandCode1(i) return s def expandCode1(s): subst = (('A1','i[1]'),('A2','i[2]'),('A3','i[3]'), ('Reg','self.reg'), ('incPC()','self.incPC()'), ('RAM','self.RAM')) for i in subst: s = string.replace(s,i[0],i[1]) return s def isNumber(str): """Verifies if a string is a number representation""" for i in str: if i not in string.digits: return 0 return 1 def validateLabelName(str,linenum): """Verifies if a candidate label name is not of the form R{num}. If the first character is a letter and only contains legal chars.""" if str[0] not in string.letters: raise LabelNameError(linenum) if str[0] in ["R","r"] and isNumber(str[1:]): raise LabelNameError(linenum) for i in str[1:]: if i not in string.letters + string.digits: raise LabelNameError(linenum) def validateString(i,n): arg = "" if i[0] != '"' or i[-1] != '"': raise WrongArg(n) flag = False for c in i[1:-1]: if not flag: if c == "\\": flag= True else: arg += c else: flag = False if c=="t": arg += "\t" if c=="s": arg += " " if c == "n": arg += "\n" if c == "\\": arg += "\\" return arg def charORint(i,n): if i[0] != "'": try: r = int(i) except ValueError: raise WrongArg(n) elif i[-1] != "'": raise WrongArg(n) elif i[1] != "\\" and len(i) != 3: raise WrongArg(n) elif i[1] != "\\": r = ord(i[1]) else: if len(i) != 4: raise WrongArg(n) elif i[2] == "n": r = ord("\n") elif i[2] == "s": r = ord(" ") elif i[2] == "t": r = ord("\t") elif i[2] == "\\": r = ord("\\") else: raise WrongArg(n) return r def isRegName(str): """Verifies if this is a register name.""" if str[0] not in ['r','R']: return 0 elif not isNumber(str[1:]): return 0 return 1 apoo-2.2/vpu_tutor.py0000640000076600000240000002545510745416725014011 0ustar rvrdialout# -*- coding: UTF-8 -*- """ The core of an exercise tester in the spirit of the Ganesh project Copyright (C) 1998-2003 Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @author: Rogério Reis & Nelma Moreira {rvr,nam}@ncc.up.pt """ from constants import * from vpu import Vpu, ReadProgram, CantRead, isNumber, isRegName import constants, vpu # constants need to be imported twice because of -v option... import sys, stat, posix, string __version = "$Id: vpu_tutor.py,v 1.29 2006-11-13 11:11:59 rvr Exp $" class Vpu_Tutor(Vpu): def doIt(self): try: input = open(self.tutorFile,'r') except IOError: CantRead(self.tutorFile) self.ggrade = 0 last, loaded, run = 'ready',0,0 tutor = [] # remove commands and create a tutor command list while 1: line = input.readline() if not line: break if len(line) == 1: continue line = string.split(line) if line: if line[0][0] == '#': continue flag = 1 for i in range(len(line)): if line[i][0] != '#' and flag: continue else: flag = 0 del(line[i]) tutor.append(line) # now lets parse and execute the tutor file for line in tutor: if not line: continue if line[0] == 'load': if last != 'ready': sys.stderr.write("error: load out of order\n") sys.exit(1) last = 'load' run = 0 elif line[0] == 'initial': if last != 'ready' or not loaded: sys.stderr.write("error: initial out of order\n") sys.exit(1) last = line[0] run = 0 labelReq1 = {} labelReq2 = {} for arg in line[1:]: if ':' in arg: a = string.split(arg,':') labelReq1[a[0]] = ParseValuesM(a[1]) elif ';' in arg: a = string.split(arg,';') labelReq2[a[0]] = int(a[1]) else: sys.stderr.write("error: bad arguments for initial\n") sys.exit(1) elif line[0] == 'init': if last == 'load': sys.stdout.write("error: Not testing the initial set of values\n") sys.exit(1) elif not loaded: sys.stdout.write("error: program not loaded\n") sys.exit(1) else: self.load(program) for arg in line[1:]: foo = string.split(arg,':') if isRegName(foo[0]): bar = int(foo[0][1:]) self.reg[bar] = int(foo[1]) else: self.VerifyLabelM(foo[0]) Values = ParseValuesM(foo[1]) # lets verify if the values fit # in the originally allocated space if len(Values) > self.labelms[foo[0]]: self.reserveMemory(foo[0],len(Values)) add = self.labelm[foo[0]] for i in Values: self.RAM[add] = i add = add + 1 last = line[0] run = 0 elif line[0] == 'exec': if not loaded: sys.stdout.write("error: program not loaded\n") sys.exit(1) else: if len(line) == 1: target = "" else: target = line[1] run = 1 last = line[0] elif line[0] == 'final' or line[0] == '+final': last = line[0] if not run: sys.stdout.write("error: need to run the program before testing the results\n") sys.exit(1) RegVal = {} LabelReq1 = {} for arg in line[1:]: foo = string.split(arg,':') if isRegName(foo[0]): RegVal[int(foo[0][1:])] = int(foo[1]) else: LabelReq1[foo[0]] = ParseValuesM(foo[1]) elif line[0] == 'end': if self.NoErrorsp(): sys.stdout.write("%d OK\n"%self.ggrade) else: sys.stdout.write("%d %s"%(self.ggrade,self.ErrMessage)) sys.exit(0) elif line[0] == 'value': grade = int(line[1]) if not last in ['load','initial','exec','final','+final']: sys.stderr.write("error: value out of order\n") sys.exit(1) elif last == 'load': program = ReadProgram(self.programFile) try: self.load(program) except vpuError, obj: self.respond(obj.message,obj.line) loaded = 1 self.ggrade = self.ggrade + grade last = 'ready' elif last == 'initial': for l in labelReq1.keys(): self.VerifyLabel1(l,labelReq1[l]) for l in labelReq2.keys(): self.VerifyLabel2(l,labelReq2[l]) self.ggrade = self.ggrade + grade elif last == 'exec': if target == "": try: self.run() except EndOfProgram: self.ggrade = self.ggrade + grade except ArithmeticError: self.respond(sys.exc_type) except vpuError, obj: self.respond(obj.message) except: # this should NEVER happen! print sys.exc_type, sys.exc_value elif last == 'final': for r in RegVal.keys(): self.VerifyReg(r,RegVal[r]) for r in LabelReq1.keys(): self.VerifyLabel1(r,LabelReq1[r]) self.ggrade = self.ggrade + grade elif last == '+final': nErrors = 0 for r in RegVal.keys(): nErrors = nErrors + self.VerifyReg(r,RegVal[r],True) for r in LabelReq1.keys(): nErrors = nErrors + self.VerifyLabel1(r,LabelReq1[r],True) if not nErrors: self.ggrade = self.ggrade + grade def VerifyReg(self, r, value, NotVital=False): if self.reg[r] != value: if NotVital: self.SetErrMsg("Register R%d does not have the right value\n"%r) return 1 else: sys.stdout.write("%d Register R%d does not have the right value\n"%(self.ggrade,r)) sys.exit(0) else: return 0 def VerifyLabelM(self,label): if not label in self.labelm.keys(): sys.stdout.write("%d Label %s not created\n"%(self.ggrade,label)) sys.exit(0) def VerifyLabel1(self, label, values, NotVital=False): self.VerifyLabelM(label) add = self.labelm[label] for v in values: try: Wrong = self.RAM[add] != v except IndexError: Wrong = True if Wrong: if NotVital: self.SetErrMsg("Label %s does not have the right value\n"%label) return 1 else: sys.stdout.write("%d Label %s does not have the right value\n"%(self.ggrade,label)) sys.exit(0) add = add + 1 return 0 def VerifyLabel2(self, label, size): self.VerifyLabelM(label) if self.labelms[label] != size: sys.stdout.write("%d Label %s does not have the right size assigned\n"%(self.ggrade,label)) sys.exit(0) def NoErrorsp(self): try: foo = self.ErrMessage except AttributeError: return True return False def SetErrMsg(self,msg): try: foo = self.ErrMessage except AttributeError: self.ErrMessage = msg def respond(self,message,line=0): if line != 0: sys.stdout.write("%d %s in line %d\n"%(self.ggrade,message,line)) sys.exit(0) else: sys.stdout.write("%d %s\n"%(self.ggrade,message)) sys.exit(0) def ParseValuesM(str): l1 = string.split(str,',') list = [] for i in l1: list.append(int(i)) return list def readable(path): try: mode = posix.stat(path)[stat.ST_MODE] except OSError: # File doesn't exist sys.stderr.write("%s not found\n"%path) sys.exit(1) if not stat.S_ISREG(mode): # or it's not readable sys.stderr.write("%s not readable\n"%path) sys.exit(1) # just to use inside pdb def test(a,b): vPu = Vpu_Tutor() vPu.tutorFile = a vPu.programFile = b vPu.doIt() if __name__ == '__main__': if (len(sys.argv) == 2 and sys.argv[1] == "-v"): sys.stderr.write("%s\n"%__version) sys.stderr.write("%s\n"%vpu.__version) sys.stderr.write("%s\n"%constants.__version) sys.exit(0) elif (len(sys.argv) != 3): sys.stderr.write("Usage: apoo-tutor tutor-file apoo-program\n") sys.exit(1) for i in [sys.argv[1],sys.argv[2]]: readable(i) vpu = Vpu_Tutor() vpu.tutorFile = sys.argv[1] vpu.programFile = sys.argv[2] vpu.doIt()