Why am I getting extra characters? - lc3

Program Description
I used .BLKW to allocate 20 locations for each character that the user inputs and for now, I just want to display the string the user typed at the first prompt. (This will be a pig latin translator, hence the second prompt; but right now I just want to see if I can print out the user input)
The Problem
The problem is that when I run it, I get extra characters at the end.
For example:
English Word: apple
Pig-Latin Word: apple
English Word: at
Pig-Latin Word: atple
English Word: set
Pig-Latin Word: setle
My Program
.ORIG x3000
START ST R1,SAVER1
ST R2,SAVER2
ST R3,SAVER3
LD R5,ENTER
REPEAT LEA R0,PROMPT ; loading the starting address of prompt
PUTS ; displays PROMPT on screen
LEA R4,ENGLWORD ; sets aside memory locations for typed characters
INPUT GETC ; now that user has typed, read char into R0
ADD R6,R5,R0 ; adds the negative value of the ASCII enter key code to the input character
BRz PIGPROMPT ; if the sum of the ASCII codes from step before is 0, that means user pressed enter so go to PIGPROMPT
OUT ; write char in R0 to console
STR R0,R4,#0 ; store typed character into memory location
ADD R4,R4,#1 ; increment memory location so you write next character to the next location
BRnzp INPUT ; break no matter what to the INPUT step to receive next typed character
PIGPROMPT LEA R0,PIG ; loads starting address of pig latin prompt
PUTS ; displays pig latin prompt on screen
LEA R0,ENGLWORD
PUTS
BRnzp REPEAT
LD R1,SAVER1 ; restore R1 to original value
LD R2,SAVER2 ; restore R2 to original value
LD R3,SAVER3 ; restore R3 to original value
HALT
SAVER1 .BLKW 1 ; allocates 1 memory location for SAVER1
SAVER2 .BLKW 1 ; allocates 1 memory location for SAVER2
SAVER3 .BLKW 1 ; allocates 1 memory location for SAVER3
ENGLWORD .BLKW #20
ENTER .FILL xFFF6 ; the negative value of the ASCII code for the enter key
NEWLINE .FILL x000A
PROMPT .STRINGZ "\nEnglish Word: " ; initializes a sequence of stringLength+1 memory locations to hold string
PIG .STRINGZ "\nPig-Latin Word: "
DSR .FILL xFE04
DDR .FILL xFE06
KBSR .FILL xFE00
KBDR .FILL xFE02
.END
Attempted Solution
I was thinking that the problem was that R4 holds the string of the first user input throughout the whole program. So for a solution, I thought about clearing R4 after it is displayed so that it's ready to take the next user input. Does anyone know how I would do that?

The key here is how PUTS works -- it prints all the characters starting at the address in R0 until it reaches a 0 ('\0' not '0').
The first time you run it, the memory will contain ['A','P','P','L','E'], followed by zeroes if you didn't randomize memory contents when you loaded the program. This means that a PUTS call will return "APPLE". When you enter the new word, it doesn't clear out that memory, so entering "at" will result in ['A','T','P','L','E'], and your print routine will print "ATPLE".
In order to properly finish the word, you need to add a '\0' (a.k.a. 0) to the element after the last character to print. In other words, if your memory contains ['A','T','\0','L','E'], your print routine will print "AT".

Aqua's right, the PUTs command is looking for a zero to stop printing characters to the screen. I've added two lines of code just after PIGPROMPT and it seems to be working as intended.
Revised:
.ORIG x3000
START ST R1,SAVER1
ST R2,SAVER2
ST R3,SAVER3
LD R5,ENTER
REPEAT LEA R0,PROMPT ; loading the starting address of prompt
PUTS ; displays PROMPT on screen
LEA R4,ENGLWORD ; sets aside memory locations for typed characters
INPUT GETC ; now that user has typed, read char into R0
ADD R6,R5,R0 ; adds the negative value of the ASCII enter keycode to the input character
BRz PIGPROMPT ; if the sum of the ASCII codes from step before is 0, that means user pressed enter so go to PIGPROMPT
OUT ; write char in R0 to console
STR R0,R4,#0 ; store typed character into memory location
ADD R4,R4,#1 ; increment memory location so you write next character to the next location
BRnzp INPUT ; break no matter what to the INPUT step to receive next typed character
PIGPROMPT AND R0, R0, #0 ; clear R0
STR R0,R4,#0 ; store typed character into memory location
LEA R0,PIG ; loads starting address of pig latin prompt
PUTS ; displays pig latin prompt on screen
LEA R0,ENGLWORD
PUTS
BRnzp REPEAT
LD R1,SAVER1 ; restore R1 to original value
LD R2,SAVER2 ; restore R2 to original value
LD R3,SAVER3 ; restore R3 to original value
HALT
SAVER1 .BLKW 1 ; allocates 1 memory location for SAVER1
SAVER2 .BLKW 1 ; allocates 1 memory location for SAVER2
SAVER3 .BLKW 1 ; allocates 1 memory location for SAVER3
ENGLWORD .BLKW #20
ENTER .FILL xFFF6 ; the negative value of the ASCII code for the enter key
NEWLINE .FILL x000A
PROMPT .STRINGZ "\nEnglish Word: " ; initializes a sequence of stringLength+1 memory locations to hold string
PIG .STRINGZ "\nPig-Latin Word: "
DSR .FILL xFE04
DDR .FILL xFE06
KBSR .FILL xFE00
KBDR .FILL xFE02
.END
All I did was store a '0' value at the end of the user's string, that way when PUTs is called it will stop at the zero value.

Related

Get Assembly without Labels

I am currently attempting to output assembly using the script below:
for instr in currentProgram.getListing().getInstructions(True):
print("\" " + str(instr) + "\\n\\t" + "\"")
It produces output like below:
" ADD RBX,0x1\n\t"
" CMP RBP,RBX\n\t"
" JNZ 0x001012b0\n\t"
" ADD RSP,0x8\n\t"
This works great for every instruction except anything that modifies the execution flow, such as jumps or calls. I'd ideally like the output to be:
" ADD RBX,0x1\n\t"
" CMP RBP,RBX\n\t"
" JNZ -0x10\n\t"
" ADD RSP,0x8\n\t"
Because in this example, the JNZ instruction jumps to an address a distance of 0x10 before this instruction. I can see this in the instruction bytes of 75 ea (75 being a jnz, and ea being -0x10), but I don't know how to get this value from the ghidra scripting api. Can you help me get this value for the output I'm expecting?

Executing TI BASIC from a String

Is it possible to Execute TI BASIC from a string? Such that:
execute(":Disp Str1")
would Print out Str1?
It could be done with a small Asm( program that takes a string (from Ans), turns it into a BASIC program, and executes it. For example:
.nolist
#include "ti83plus.inc"
.list
.org userMem-2
.db $BB,$6D
ld hl,SavesScreen
ld (hl),tTheta
inc hl
ld (hl),0
inc hl
push hl
bcall(_AnsName)
rst rFindSym
ex de,hl
ld c,(hl)
inc hl
ld b,(hl)
dec hl
inc bc
inc bc
pop de
ldir
ld hl,SavesScreen
ld a,6
bcall(_ExecuteNewPrgm)
; no ret because _ExecuteNewPrgm does not return
This is not ideal,
No safety in case Ans did not contain a string (could be added).
A program named θ should not exist, because it will be overwritten. If prgmθ already exists and is archived, then it does not work at all. (could be improved)
prgmθ is not deleted afterwards. (not sure how to do this)
When prgmθ is done, it quits to the Homescreen, it does not return to the calling program. (not sure how to do this)
Aside from that, it does work, for example:
:"TESTING->Str1
:":Disp Str1
:Asm(prgmRUNSTR
Looks like this afterwards:
You can create the assembly program by typing this into a normal program:
AsmPrgmBB6D21
EC86365B2336
0023E5EF524B
D7EB4E23462B
0303D1EDB021
EC863E06EF3C
4C
It can be made smaller with AsmComp(.
Unfortunately, no, not like this- expr and eval only work on expressions.

EBNF: prefix and suffix-like operator in assembly code production

I'm trying to write down 6809 assembly in EBNF to write a tree-sitter parser.
I'm stuck on one certain production. In 6809 assembly, you can use a register as an operand and additionally de- or increment it:
LDA 0,X+ ; loads A from X then bumps X by 1
LDD ,Y++ ; loads D from Y then bumps Y by 2
LDA 0,-U ; decrements U by 1 then loads A from address in U
LDU ,--S ; decrements S by 2 then loads U from address in S
Mind the "missing" first operand in the second line of code. Here are the productions I wrote:
instruction = opcode, [operand], ["," , register_exp];
...
register_exp = [{operator}], register | register, [{operator}];
register = "X" | "Y" | "U" | etc. ;
operator = "+" | "-";
The problem is register_exp = .... I feel like there could be a more elegant way to define this production. Also, what happens if only a register is given to register_exp?
You probably need
register_exp = [{operator}], register | register, [{operator}] | register;
to allow register names without operators. Why do you find it not so elegant? Quite descriptive.

LC-3, LDI isn't getting right address?

My code below is supposed to simply print a prompt, but it's printing a bunch of y-looking characters instead. Any idea of what I'm doing wrong?
CODE:
startPrompt .STRINGZ "Enter 'E' to encrpyt, 'D' to decrpyt, X to quit\n"
startPromptAddress .FILL startPrompt
LDI R0, startPromptAddress
PUTS
I think you want LEA, not LDI.
LEA Loads a register with the ADDRESS of LABEL (not its contents!). Often used with .STRINGZ and PUTS to print a string.
LDI gets the address that is stored at the LABEL (or an offset), and then gets the VALUE at THAT address (this is the indirect "i" part of LDI).
Here's the full code that should work in a typical LC3 simulator (I used the one at lc3tutor.org to verify:
--------------- cut here ---------------
.ORIG x3000
startPrompt .STRINGZ "Enter 'E' to encrpyt, 'D' to decrpyt, X to quit\n"
LEA R0, startPrompt; load the address at 'startPrompt' into R0
PUTS; print characters starting at R0 and continuing until the null character is reached (automatically part of the memory initialized when you use the .STRINGZ directive).
.END
-------------- cut here ---------------
Hope this helps
Jeff

COBOL illegal file name

IDENTIFICATION DIVISION.
PROGRAM-ID. HENSEM as "Test1.Program1".
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CUSTOMER-FILE
ASSIGN TO "CUSTOMER.DAT"
ORGANIZATION IS SEQUENTIAL.
SELECT PRINTER-FILE
ASSIGN TO PRINTER
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD CUSTOMER-FILE
LABEL RECORDS ARE STANDARD.
01 CUSTOMER-RECORD.
05 CUSTOMER-NAME PIC X(30).
05 CUSTOMER-PRODUCT PIC X(20).
05 CUSTOMER-QUANTITY PIC 9(2).
05 CUSTOMER-DATE PIC X(10).
FD PRINTER-FILE
LABEL RECORDS ARE OMITTED.
01 PRINTER-RECORD PIC X(80).
WORKING-STORAGE SECTION.
*VARIABLES FOR SCREEN ENTRY
01 Y-N PIC X.
01 ENTRY-STATUS PIC X.
PROCEDURE DIVISION.
OPEN EXTEND CUSTOMER-FILE.
OPEN OUTPUT PRINTER-FILE.
MOVE "Y" TO Y-N.
PERFORM ADD-RECORDS
UNTIL Y-N = "N".
PERFORM CLOSING-PROCEDURE.
GOBACK.
* OPENING AND CLOSING
OPENING-PROCEDURE.
CLOSING-PROCEDURE.
CLOSE CUSTOMER-FILE.
MOVE SPACE TO PRINTER-RECORD.
WRITE PRINTER-RECORD BEFORE ADVANCING PAGE.
CLOSE PRINTER-FILE.
ADD-RECORDS.
MOVE "N" TO ENTRY-STATUS.
PERFORM GET-FIELDS
UNTIL ENTRY-STATUS = "Y".
PERFORM ADD-THIS-RECORD.
PERFORM ANY-MORE.
GET-FIELDS.
MOVE SPACE TO CUSTOMER-RECORD.
DISPLAY "ENTER CUSTOMER NAME: ".
ACCEPT CUSTOMER-NAME.
DISPLAY "ENTER WHAT DID THE CUSTOMER BOUGHT: ".
ACCEPT CUSTOMER-PRODUCT.
DISPLAY "ENTER HOW MUCH DID THE CUSTOMER BOUGHT: ".
ACCEPT CUSTOMER-QUANTITY.
DISPLAY "ENTER WHEN DID THE CUSTOMER BOUGHT: ".
ACCEPT CUSTOMER-DATE.
PERFORM VALIDATE-FIELDS.
VALIDATE-FIELDS.
MOVE "Y" TO ENTRY-STATUS.
IF CUSTOMER-NAME = SPACE
DISPLAY "CUSTOMER NAME MUST BE ENTERED"
MOVE "N" TO ENTRY-STATUS.
ADD-THIS-RECORD.
MOVE CUSTOMER-RECORD TO PRINTER-RECORD.
WRITE CUSTOMER-RECORD.
WRITE PRINTER-RECORD BEFORE ADVANCING 1.
ANY-MORE.
DISPLAY "IS THERE ANY MORE INPUT?".
ACCEPT Y-N.
IF Y-N = "Y"
MOVE "Y" TO Y-N.
IF Y-N NOT = "Y"
MOVE "N" TO Y-N.
END PROGRAM HENSEM.
My problem is the OPEN OUTPUT FILE-PRINTER LINE. The program does not run and I'm getting illegal file-name error. If I delete that whole line, it runs but later produces error at WRITE PRINTER-RECORD BEFORE ADVANCING 1. Thank you.
You can assign a device name to your file using one of the standard Windows symbolic names, instead of the COBOL keyword PRINTER:
SELECT PRINTER-FILE
ASSIGN TO "lpt1"
ORGANIZATION IS LINE SEQUENTIAL.

Resources