Part Tatlo - Looping, wonderful looping
(This is the third part in my Diving into INTERCAL series. If you have read the first two parts then don't feel cocky because the following will probably not make any more sense to you than to a total INTERCAL beginner.)
In this excursion into the magical world of INTERCAL programming we will try to do the almost impossible, create a program with a while loop. If you have programmed in any imperative programming language, such as C, Java, Python or Commodore BASIC, you will know that loops are usually a straight-forward construct. However INTERCAL is designed from the ground up to be like no other language, so let's see if we can actually get a loop to work.
Having taken nearly two hours to write 'Hello, world' last week, I decided to set my sights fairly low for this week. I want to implement the following Python program in INTERCAL:
Anyone with any amount of experience knows that it would be a folly to attempt to convert this program to INTERCAL in one shot. It is much more wise to perform the conversion in small steps. Here is my first iteration:
1 DON'T...: Any statement which starts with DO NOT, PLEASE NOT, DON'T or PLEASE DON'T will simply be ignored by INTERCAL. The rest of the statement does not need to be valid INTERCAL syntax because since you don't want to do it the compiler doesn't have to understand it.
2 PLEASE NOTE...: Because of the rule above, many INTERCAL programs include 'PLEASE NOTE' as a way of including comments. INTERCAL only cares about the first three letters of NOT, so PLEASE NOTCH MY BELT would also be ignored.
Line two also introduces the idea of a label, (1), which in this iteration is not actually used. Labels are given numbers, not names.
In keeping with good programming practices, the comment 'PLEASE NOTE THAT WE ARE NOT PROMPTING' is 100% accurate. If you have read 'Hello, world' earlier, you will know that writing character output is just not worth the effort. Usability is overrated.
3 DO WRITE IN .1: In this statement we are asking INTERCAL to accept numeric input from the user, storing the input in the 16-bit variable .1. 16-bit variables are represented with the 'spot' (.), whilst 32-bit variables are represented with the 'two spot' (:). In INTERCAL you have 65535 16-bit variables and the same number of 32-bit variables, from .1 to .65535 and :1 to :65535. Note that .1 and .001 are the same variable, but .1 and :1 are not.
4 DO READ OUT .001: In this statement we are asking INTERCAL to send the value of variable .001 (which is the same as .1, .01, etc) to the standard output. For your convenience, the number is output in Roman numerals.
5 DO GIVE UP: Ends the program.
If I compile and run the above program it will accept my input (eg. ONE TWO THREE), output the number (eg. CXXIII) and then exit. Too easy.
If at line 5 we insert the statement 'PLEASE DO (1) NEXT', the program will jump to our label (1) instead of exiting. The program will continue looping forever, which is certainly a step in the right direction of converting our Python program to INTERCAL.
The program continues looping until the user types in invalid input. For example if I type in the input 'WHAT IS UP DOC?', the program will respond:
ICL579I WHAT BASE AND/OR LANGUAGE INCLUDES WHAT?
ON THE WAY TO 4
CORRECT SOURCE AND RESUBNIT
I am not going to try to add input validation or error handling to this program because life is simply too short. But the program still falls short of the Python original - it does not exit if the input is equal to 1. We need an IF statement.
By now we should guess that INTERCAL will not have an IF statement, and we would be correct. In keeping with the 'unlike any other language' theme, there is nothing that really approximates an IF statement at all. It turns out that implementing an IF is quite a difficult task in INTERCAL.
Here is my the next iteration of our program, trying to get around INTERCAL's lack of an IF:
2 DO (2) NEXT: When we added the DO (1) NEXT line earlier, you may have assumed that it was a BASIC-style GOTO. Unlike BASIC's GOTO, the position of the next statement after a DO (in this case line 3) is placed onto a 'NEXT' stack. This NEXT stack can be manipulated by the RESUME or FORGET statements, discussed later.
7 (2) DO (1) NEXT: This is the statement which the previous statement jumped to. We simply jump straight back to label (1). Note that this statement will also push the position of line 8, DO GIVE UP, onto the NEXT stack. At this point the NEXT stack will look like this:
Line 8
Line 3
6 PLEASE RESUME .1: This is the most important line in the program. When we reach this point we have the user's input in the variable .1 and have just sent it to the output. We need to decide whether to continue looping. The RESUME statement will evaluate the expression, in this case the value of .1, and pop that many items off the NEXT stack. It will then jump to the last item popped.
So if the user types in 'ONE' the program will pop the top item from the NEXT stack and then jump to Line 8, the end of the program. This is exactly what we wanted.
Alternatively, if the user types in 'TWO' (or maybe 'DALAWA') then two items will be popped and the program will jump to line 3. This is also exactly what we wanted, because the user will then continue the loop at line 3.
So we are finished right?
Um, no. If the user types anything other than ONE or TWO (or any number at all on the second iteration) then they will receive the following message:
ICL632I THE NEXT STACK RUPTURES. ALL DIE. OH, THE EMBARRASSMENT!
ON THE WAY TO 8
CORRECT SOURCE AND RESUBNIT
Oh dear, it seems we still have a bit more learning to do before we will have mastered the IF construct in INTERCAL. Unfortunately I am very sleepy, and also incredibly confused, so the completion of this program will need to wait for another day. Stay tuned.
Are you an INTERCAL guru? Please feel free to post the solution as a comment. (It will sure save me from figuring it out.)
Desperately waiting to see how this program is written in INTERCAL? Subscribe to the 'Diving into INTERCAL' feed and you will be the first to know.
In this excursion into the magical world of INTERCAL programming we will try to do the almost impossible, create a program with a while loop. If you have programmed in any imperative programming language, such as C, Java, Python or Commodore BASIC, you will know that loops are usually a straight-forward construct. However INTERCAL is designed from the ground up to be like no other language, so let's see if we can actually get a loop to work.
Having taken nearly two hours to write 'Hello, world' last week, I decided to set my sights fairly low for this week. I want to implement the following Python program in INTERCAL:
x = 0This is by no means a useful program - it simply asks the user repeatedly to type in a number, printing it out each time, until the user enters a number which is not equal to 1.
while(x != 1):
x = int(raw_input("Please input a number\n"))
print x
Anyone with any amount of experience knows that it would be a folly to attempt to convert this program to INTERCAL in one shot. It is much more wise to perform the conversion in small steps. Here is my first iteration:
1 DON'T WORRY, BE HAPPYThe line numbers are not part of the program. (This is not BASIC.) Here is a line by line analysis of the program:
2 (1) PLEASE NOTE THAT WE ARE NOT PROMPTING
3 DO WRITE IN .1
4 DO READ OUT .001
5 DO GIVE UP
1 DON'T...: Any statement which starts with DO NOT, PLEASE NOT, DON'T or PLEASE DON'T will simply be ignored by INTERCAL. The rest of the statement does not need to be valid INTERCAL syntax because since you don't want to do it the compiler doesn't have to understand it.
2 PLEASE NOTE...: Because of the rule above, many INTERCAL programs include 'PLEASE NOTE' as a way of including comments. INTERCAL only cares about the first three letters of NOT, so PLEASE NOTCH MY BELT would also be ignored.
Line two also introduces the idea of a label, (1), which in this iteration is not actually used. Labels are given numbers, not names.
In keeping with good programming practices, the comment 'PLEASE NOTE THAT WE ARE NOT PROMPTING' is 100% accurate. If you have read 'Hello, world' earlier, you will know that writing character output is just not worth the effort. Usability is overrated.
3 DO WRITE IN .1: In this statement we are asking INTERCAL to accept numeric input from the user, storing the input in the 16-bit variable .1. 16-bit variables are represented with the 'spot' (.), whilst 32-bit variables are represented with the 'two spot' (:). In INTERCAL you have 65535 16-bit variables and the same number of 32-bit variables, from .1 to .65535 and :1 to :65535. Note that .1 and .001 are the same variable, but .1 and :1 are not.
4 DO READ OUT .001: In this statement we are asking INTERCAL to send the value of variable .001 (which is the same as .1, .01, etc) to the standard output. For your convenience, the number is output in Roman numerals.
5 DO GIVE UP: Ends the program.
If I compile and run the above program it will accept my input (eg. ONE TWO THREE), output the number (eg. CXXIII) and then exit. Too easy.
If at line 5 we insert the statement 'PLEASE DO (1) NEXT', the program will jump to our label (1) instead of exiting. The program will continue looping forever, which is certainly a step in the right direction of converting our Python program to INTERCAL.
The program continues looping until the user types in invalid input. For example if I type in the input 'WHAT IS UP DOC?', the program will respond:
ICL579I WHAT BASE AND/OR LANGUAGE INCLUDES WHAT?
ON THE WAY TO 4
CORRECT SOURCE AND RESUBNIT
I am not going to try to add input validation or error handling to this program because life is simply too short. But the program still falls short of the Python original - it does not exit if the input is equal to 1. We need an IF statement.
By now we should guess that INTERCAL will not have an IF statement, and we would be correct. In keeping with the 'unlike any other language' theme, there is nothing that really approximates an IF statement at all. It turns out that implementing an IF is quite a difficult task in INTERCAL.
Here is my the next iteration of our program, trying to get around INTERCAL's lack of an IF:
1 DON'T WORRY, BE HAPPYExplaining the additional lines:
2 DO (2) NEXT
3 (1) PLEASE NOTE THAT WE ARE NOT PROMPTING
4 DO WRITE IN .1
5 DO READ OUT .001
6 PLEASE RESUME .1
7 (2) DO (1) NEXT
8 DO GIVE UP
2 DO (2) NEXT: When we added the DO (1) NEXT line earlier, you may have assumed that it was a BASIC-style GOTO. Unlike BASIC's GOTO, the position of the next statement after a DO (in this case line 3) is placed onto a 'NEXT' stack. This NEXT stack can be manipulated by the RESUME or FORGET statements, discussed later.
7 (2) DO (1) NEXT: This is the statement which the previous statement jumped to. We simply jump straight back to label (1). Note that this statement will also push the position of line 8, DO GIVE UP, onto the NEXT stack. At this point the NEXT stack will look like this:
Line 8
Line 3
6 PLEASE RESUME .1: This is the most important line in the program. When we reach this point we have the user's input in the variable .1 and have just sent it to the output. We need to decide whether to continue looping. The RESUME statement will evaluate the expression, in this case the value of .1, and pop that many items off the NEXT stack. It will then jump to the last item popped.
So if the user types in 'ONE' the program will pop the top item from the NEXT stack and then jump to Line 8, the end of the program. This is exactly what we wanted.
Alternatively, if the user types in 'TWO' (or maybe 'DALAWA') then two items will be popped and the program will jump to line 3. This is also exactly what we wanted, because the user will then continue the loop at line 3.
So we are finished right?
Um, no. If the user types anything other than ONE or TWO (or any number at all on the second iteration) then they will receive the following message:
ICL632I THE NEXT STACK RUPTURES. ALL DIE. OH, THE EMBARRASSMENT!
ON THE WAY TO 8
CORRECT SOURCE AND RESUBNIT
Oh dear, it seems we still have a bit more learning to do before we will have mastered the IF construct in INTERCAL. Unfortunately I am very sleepy, and also incredibly confused, so the completion of this program will need to wait for another day. Stay tuned.
Are you an INTERCAL guru? Please feel free to post the solution as a comment. (It will sure save me from figuring it out.)
Desperately waiting to see how this program is written in INTERCAL? Subscribe to the 'Diving into INTERCAL' feed and you will be the first to know.
Labels: IF, Looping, Premature Baldness