NCL 205: Comparing and Interpreting Strings
In NCL 204, we took a structured string like:
EMMA:hello
and extracted two separate strings:
#name = "EMMA"
#text = "hello"
Once we have those pieces, we can do more than display them.
We can make decisions based on what they contain.
Comparing strings
We've already used BEQ to compare integers.
For example:
BEQ $five r0 5
branches to $five if the value in r0 is equal to 5.
Strings have their own equality branch: BSEQ.
#name s0
SMOVE #name "EMMA"
BSEQ $emma #name "EMMA"
D.TXT "Someone else"
JUMP $done
$emma
D.TXT "Hello, Emma"
$done
D.BLT
The program displays:
Hello, Emma
BSEQ compares two strings and branches if they are equal.
In this case:
BSEQ $emma #name "EMMA"
asks whether the string stored in #name is equal to "EMMA".
If it is, the next instruction comes from $emma.
If it isn't, execution continues with the instruction below the BSEQ.
Try changing:
SMOVE #name "EMMA"
to:
SMOVE #name "ALICE"
The comparison is now false, so the branch isn't taken.
The program displays:
Someone else
Equal and not equal
There is also BSNEQ.
It branches if two strings are not equal.
For example:
BSNEQ $other #name "EMMA"
branches to $other if #name contains anything other than "EMMA".
The integer and string equality branches correspond closely:
| Integers | Strings | Branch when |
|---|---|---|
BEQ |
BSEQ |
equal |
BNEQ |
BSNEQ |
not equal |
The important difference is what they compare.
BEQ and BNEQ compare integer values.
BSEQ and BSNEQ compare strings.
Capitalization matters
String comparisons are case-sensitive.
These strings are different:
EMMA
Emma
emma
For example:
#name s0
SMOVE #name "Emma"
BSEQ $emma #name "EMMA"
D.TXT "No match"
JUMP $done
$emma
D.TXT "Match"
$done
D.BLT
displays:
No match
Sometimes that's exactly what we want.
Other times, capitalization shouldn't matter.
We already know how to handle that.
#name s0
SMOVE #name "Emma"
SUPR #name #name
BSEQ $emma #name "EMMA"
D.TXT "No match"
JUMP $done
$emma
D.TXT "Match"
$done
D.BLT
SUPR changes the value in #name to:
EMMA
before the comparison.
Now the program displays:
Match
Instead of asking BSEQ to perform a different kind of comparison, we change the strings into a consistent form first.
We used the same technique with SFIND in NCL 203.
Interpreting a string
Let's give our extracted strings a more useful job.
Suppose we have:
SAY:Hello!
Using the techniques from NCL 204, we can split that into:
#command = "SAY"
#argument = "Hello!"
For now, suppose that work has already been done:
#command s0
#argument s1
SMOVE #command "SAY"
SMOVE #argument "Hello!"
We can use BSEQ to decide what the command means:
BSEQ $say #command "SAY"
D.TXT "Unknown command"
JUMP $done
$say
D.TXT #argument
$done
D.BLT
Because #command contains "SAY", the program branches to:
$say
and displays:
Hello!
Change:
SMOVE #command "SAY"
to:
SMOVE #command "BANANA"
and neither the string nor BSEQ knows what "BANANA" is supposed to mean.
The program simply doesn't take the branch, so it displays:
Unknown command
BSEQ does not understand commands.
It only compares strings.
The meaning of "SAY" comes from what our program does when that comparison succeeds.
More than one command
One comparison gives us one recognized command.
More comparisons give us more possibilities.
Let's add:
SHOUT
#command s0
#argument s1
SMOVE #command "SHOUT"
SMOVE #argument "Hello!"
BSEQ $say #command "SAY"
BSEQ $shout #command "SHOUT"
D.TXT "Unknown command"
JUMP $done
$say
D.TXT #argument
JUMP $done
$shout
SUPR #argument #argument
D.TXT #argument
$done
D.BLT
The program checks:
BSEQ $say #command "SAY"
That comparison fails, so execution continues.
Then it checks:
BSEQ $shout #command "SHOUT"
That comparison succeeds.
Execution moves to $shout, where:
SUPR #argument #argument
changes the argument to uppercase before displaying it.
The result is:
HELLO!
We have built another chain of decisions, much like the ones we used with numbers in NCL 109.
The first matching branch determines which path the program follows.
If none match, execution reaches:
D.TXT "Unknown command"
which acts as our default path.
Normalizing the command
Our current commands are case-sensitive.
That means:
SAY
works, but:
say
doesn't.
For a command language, we might decide that capitalization shouldn't matter.
We can normalize the command before comparing it:
SUPR #command #command
BSEQ $say #command "SAY"
BSEQ $shout #command "SHOUT"
Now all of these become "SAY" before the comparisons:
SAY
say
Say
sAy
Notice that we only change #command.
We leave #argument alone.
For:
say:Hello, Emma!
we want the command to be interpreted without caring about capitalization, while preserving:
Hello, Emma!
exactly as it was supplied.
Choosing which values to transform can be just as important as choosing the transformation itself.
Putting the pieces together
Now let's combine the splitting from NCL 204 with the comparisons from this lesson.
Our input will have the form:
COMMAND:argument
First, we find and validate the separator.
Then we extract the command and argument.
Finally, we interpret the command.
#separator r0
#length r1
#last r2
#leftEnd r3
#rightStart r4
#command s0
#argument s1
#input "SHOUT:Hello, Emma!"
SFIND #separator #input ":"
BEQ $invalid #separator -1
BEQ $invalid #separator 0
SLEN #length #input
MOVE #last #length
DEC #last
BEQ $invalid #separator #last
MOVE #leftEnd #separator
DEC #leftEnd
MOVE #rightStart #separator
INC #rightStart
SSUB #command #input 0 #leftEnd
SSUB #argument #input #rightStart -1
SUPR #command #command
BSEQ $say #command "SAY"
BSEQ $shout #command "SHOUT"
D.TXT "Unknown command"
JUMP $done
$say
D.TXT #argument
JUMP $done
$shout
SUPR #argument #argument
D.TXT #argument
JUMP $done
$invalid
D.TXT "Invalid input"
$done
D.BLT
With:
#input "SHOUT:Hello, Emma!"
the program displays:
HELLO, EMMA!
Change the input to:
#input "say:Hello, Emma!"
and it displays:
Hello, Emma!
The command was normalized before being interpreted.
The argument wasn't.
Our program now follows a complete sequence:
- Find the separator.
- Check that the separator is usable.
- Extract the command and argument.
- Normalize the command.
- Compare the command against the commands we recognize.
- Choose the corresponding behavior.
None of these steps is especially complicated on its own.
Combining them lets a simple string describe what a program should do.
Try it
Add a third command:
WHISPER:Hello, WORLD!
When the command is WHISPER, display its argument in lowercase.
The result should be:
hello, world!
You'll need another comparison:
BSEQ $whisper #command "WHISPER"
and another path:
$whisper
You have already used the instruction that converts a string to lowercase.
Try your program with:
WHISPER:NCS/E READY
and predict what it will display before running it.
Then add another command:
REPEAT:Hello!
Make it display:
Hello! Hello!
This one doesn't require a new string operation at all.
You already have the argument.
You just need to decide what to do with it.
We can now extract pieces from structured text and choose behavior based on what those pieces contain.
In NCL 206: Building and Formatting Strings, we'll start constructing strings into useful layouts and formats.