Spaghetti programming language by Jeffry Johnston Sept 14, 2001 Introduction ------------ This is an experiment in making a shorthand-type programming language. If you don't like GOTO you won't like this language. However, if you do like GOTO you still might not like this language :) Designed to produce "spaghetti" code, to the point where every program line can be arranged pretty much randomly and the program should still function properly. Memory ------ There is one large block of 8-bit memory. On program load the first 256 bytes of memory will contain the values 0-255, location 256 will equal 26 and location 257 will equal 1. The rest of the memory will be zeroed. Any byte of memory can be changed. Variables --------- The variables "a" through "z" are used together as a combined pointer, and are located from memory locations 256 to 281. Pointers "a" and "b" together ("b" automatically being the high byte) allows for 65536 bytes of memory to be accessed. Operations on "a" through "z" will modify only the byte involved. For example, assume that "a" is 255 and "b" is 7. If 2 is added to "a", then "a" will equal 1 and "b" will still equal 7. If addressing up to "z" is used, you'd need at least 4.11*10^62 bytes of memory ;). I imagine that most programs will only need "a" and "b". The variable "*" is similar to the C dereference, useful for modifying or grabbing the byte of memory at the combined pointer. This will initially point to location 282 because of locations 256 and 257. To reference a specific byte of memory, use a decimal number to represent the array element. For an immediate value, use numbers less than 256. Examples: Spaghetti Basic 1776 m(1776) 65 m(65) or 65, unless m(65) was modified 256 m(256) or m(a) b m(257) or m(b) * m(...+256*b+a) Commands -------- Spaghetti Basic C line[ line line:; x=y x=y x=y; x+y x=x+y x+=y; x-y x=x-y x-=y; x&y x=x AND y x&=y; x? x=ASC(INPUT$(1)) x=(char)getchar(); ?x PRINT CHR$(x); putchar(x); x48 PRINT CHR$(A); 100[284=*]101 'A=N 110[283+1]800 207[283+1]800 206[?101]207 205[?108]206 204[?116]205 203[?116]204 202[?111]203 201[?98]202 200[?32]201 '200 PRINT " bottle"; 302[283+1]800 301[?115]302 300[*~1:302]301 '300 IF N<>1 THEN PRINT "s"; 400[?32]401 '400 PRINT " of beer"; 402[?102]403 401[?111]402 404[?98]405 403[?32]404 406[?101]407 405[?101]406 408[283+1]800 407[?114]408 500[?32]501 '500 PRINT " on the wall"; 503[?32]504 502[?110]503 505[?104]506 504[?116]505 506[?101]507 508[?119]509 511[?108]512 507[?32]508 509[?97]510 512[283+1]800 510[?108]511 501[?111]502 601[?10]602 600[?13]601 '600 PRINT 602[283+1]800 700[?84]701 '700 PRINT "Take one down, pass it around"; 703[?101]704 706[?110]707 709[?100]710 712[?110]713 715[?112]716 718[?115]719 721[?116]722 724[?114]725 727[?110]728 701[?97]702 704[?32]705 707[?101]708 710[?111]711 713[?44]714 716[?97]717 719[?32]720 722[?32]723 725[?111]726 728[?100]729 702[?107]703 705[?111]706 708[?32]709 711[?119]712 714[?32]715 717[?115]718 720[?105]721 723[?97]724 726[?117]727 729[283+1]800 Spaghetti Compiler ------------------ 'SPAGHETT.BAS -- Spaghetti program compiler for Microsoft QuickBasic 'Programmed by Jeffry Johnston, September 16, 2001 'Can output Basic, C, or ASM code. DEFINT A-Z PRINT "Spaghetti compiler, Programmed by Jeffry Johnston": PRINT INPUT "Enter filename of Spaghetti source [.SPG]: ", F$ F = INSTR(F$, ".") IF F = 0 THEN E$ = ".SPG" ELSE E$ = MID$(F$, F): F$ = MID$(F$, 1, F - 1) PRINT "1) QuickBasic" PRINT "2) GW-BASIC / BasicA" PRINT "3) C" PRINT "4) A86 (MS-DOS)" PRINT "5) MASM (MS-DOS)" DO: INPUT "Choose output format: ", O: LOOP WHILE O < 1 OR O > 5 SELECT CASE O CASE 1, 2 O$ = ".BAS" CASE 3 O$ = ".C" CASE 4, 5 O$ = ".ASM" END SELECT OPEN F$ + E$ FOR INPUT AS #1 OPEN F$ + O$ FOR OUTPUT AS #2 PRINT "Writing "; F$; O$; "..." SELECT CASE O CASE 1 PRINT #2, "DEFINT A-Z" PRINT #2, "DIM M(30000)" PRINT #2, "FOR P = 0 TO 255: M(P) = P: NEXT P" PRINT #2, "OPEN " + CHR$(34) + "CONS:" + CHR$(34) + " FOR OUTPUT AS #1" PRINT #2, "M(256) = 26: M(257) = 1" PRINT #2, "GOTO 1" CASE 2 PRINT #2, "0 DEFINT A-Z: DIM M(20000): FOR P = 0 TO 255: M(P) = P: NEXT P: OPEN " + CHR$(34) + "CONS:" + CHR$(34) + " FOR OUTPUT AS #1: M(256) = 26: M(257) = 1: GOTO 1" CASE 3 PRINT #2, "#include " PRINT #2, "#include " PRINT #2, "int main(void) {" PRINT #2, " char m[32767],*p=m,*x,*y;" PRINT #2, " int i;" PRINT #2, " memset(m,0,32768);" PRINT #2, " for(i=0;i<256;i++,p++) *p=i;" PRINT #2, " m[256]=26; m[257]=1;" PRINT #2, " goto l1;" CASE 4 PRINT #2, "PROGRAM PROC NEAR" PRINT #2, " MOV DI,OFFSET M" PRINT #2, " XOR AX,AX" PRINT #2, "ASCII: STOSB" PRINT #2, " INC AL" PRINT #2, " JNZ ASCII" PRINT #2, " MOV CX,16256" PRINT #2, " REP STOSW" PRINT #2, " MOV BYTE PTR M[256],26" PRINT #2, " MOV BYTE PTR M[257],1" PRINT #2, " JMP L1" CASE 5 PRINT #2, "DOSSEG" PRINT #2, ".MODEL SMALL" PRINT #2, ".STACK 100h" PRINT #2, ".DATA" PRINT #2, " M DB 32768 DUP (?)" PRINT #2, ".CODE" PRINT #2, "PROGRAM PROC NEAR" PRINT #2, " MOV AX,DGROUP" PRINT #2, " MOV DS,AX" PRINT #2, " MOV ES,AX" PRINT #2, " MOV DI,OFFSET M" PRINT #2, " XOR AX,AX" PRINT #2, "ASCII: STOSB" PRINT #2, " INC AL" PRINT #2, " JNZ ASCII" PRINT #2, " MOV CX,16256" PRINT #2, " REP STOSW" PRINT #2, " MOV BYTE PTR M[256],26" PRINT #2, " MOV BYTE PTR M[257],1" PRINT #2, " JMP L1" END SELECT L1 = -1: L2 = -1 DO WHILE NOT EOF(1) LINE INPUT #1, A$: A$ = LTRIM$(RTRIM$(A$)) IF A$ = "" THEN GOTO L00P A$ = A$ + "@": L = L + 1 S = 1: GOSUB GETNUM IF L1 = N OR L2 = N THEN E$ = "Invalid line order": GOTO EROR ELSE L2 = -1 SELECT CASE O CASE 1, 2 PRINT #2, N$ + " "; CASE 3 PRINT #2, "l" + N$ + ":;" CASE 4, 5 PRINT #2, "L" + N$ + ":" END SELECT IF MID$(A$, S + 1, 1) <> "[" THEN E$ = "Missing line number": GOTO EROR S = S + 2 C$ = "": IF MID$(A$, S, 1) = "?" THEN S = S + 1: C$ = "#" V$ = "X": GOSUB PARSE IF C$ = "" THEN C$ = MID$(A$, S, 1): S = S + 1 IF C$ <> "#" AND C$ <> "?" THEN V$ = "Y": GOSUB PARSE SELECT CASE C$ CASE "=" SELECT CASE O CASE 1, 2 PRINT #2, "M(X) = M(Y): "; CASE 3 PRINT #2, " *x=*y;"; CASE 4, 5 PRINT #2, " MOV AL,[SI]" PRINT #2, " MOV [DI],AL" END SELECT CASE "+" SELECT CASE O CASE 1, 2 PRINT #2, "M(X) = (M(X) + M(Y)) MOD 256: "; CASE 3 PRINT #2, " *x=(*x+*y)%256;"; CASE 4, 5 PRINT #2, " MOV AL,[SI]" PRINT #2, " ADD [DI],AL" END SELECT CASE "-" SELECT CASE O CASE 1, 2 PRINT #2, "M(X) = (256 + M(X) - M(Y)) MOD 256: "; CASE 3 PRINT #2, " *x=(256+*x-*y)%256;"; CASE 4, 5 PRINT #2, " MOV AL,[SI]" PRINT #2, " SUB [DI],AL" END SELECT CASE "&" SELECT CASE O CASE 1, 2 PRINT #2, "M(X) = M(X) AND M(Y): "; CASE 3 PRINT #2, " *x&=*y;"; CASE 4, 5 PRINT #2, " MOV AL,[SI]" PRINT #2, " AND [DI],AL" END SELECT CASE "?" SELECT CASE O CASE 1, 2 PRINT #2, "M(X) = ASC(INPUT$(1)): "; CASE 3 PRINT #2, " *x=(char)getchar();"; CASE 4, 5 PRINT #2, " MOV AH,08h" PRINT #2, " INT 21h" PRINT #2, " MOV [DI],AL" END SELECT CASE "#" SELECT CASE O CASE 1 PRINT #2, "PRINT #1, CHR$(M(X)); : "; CASE 2 PRINT #2, "IF M(X) <> 10 THEN PRINT #1, CHR$(M(X)); : "; CASE 3 PRINT #2, " putchar(*x);"; CASE 4, 5 PRINT #2, " MOV AH,02h" PRINT #2, " MOV DL,[DI]" PRINT #2, " INT 21h" END SELECT CASE "<" S = S + 1: GOSUB GETNUM: S = S + 1: L2 = N SELECT CASE O CASE 1, 2 PRINT #2, "IF M(X) < M(Y) THEN "; GOSUB GTO PRINT #2, " ELSE "; CASE 3 PRINT #2, " if (*x<*y) "; GOSUB GTO PRINT #2, " else"; CASE 4, 5 PRINT #2, " MOV AL,[SI]" PRINT #2, " CMP [DI],AL" T = T + 1 PRINT #2, " JAE T" + LTRIM$(STR$(T)) GOSUB GTO PRINT #2, "T" + LTRIM$(STR$(T)) + ":" END SELECT CASE "~" S = S + 1: GOSUB GETNUM: S = S + 1: L2 = N SELECT CASE O CASE 1, 2 PRINT #2, "IF M(X) = M(Y) THEN "; GOSUB GTO PRINT #2, " ELSE "; CASE 3 PRINT #2, " if (*x==*y)"; GOSUB GTO PRINT #2, " else"; CASE 4, 5 PRINT #2, " MOV AL,[SI]" PRINT #2, " CMP [DI],AL" T = T + 1 PRINT #2, " JNZ T" + LTRIM$(STR$(T)) GOSUB GTO PRINT #2, "T" + LTRIM$(STR$(T)) + ":" END SELECT END SELECT IF MID$(A$, S, 1) <> "]" THEN E$ = "Missing jump": GOTO EROR S = S + 1: GOSUB GETNUM: L1 = N GOSUB GTO A$ = MID$(A$, 1, LEN(A$) - 1) V = INSTR(MID$(A$, S), "'") SELECT CASE O CASE 1, 2 IF V = 0 THEN PRINT #2, "" ELSE PRINT #2, " " + MID$(A$, S + V - 1) CASE 3 IF V = 0 THEN PRINT #2, "" ELSE PRINT #2, " /* " + MID$(A$, S + V) + " */" CASE 4, 5 IF V > 0 THEN PRINT #2, "; " + MID$(A$, S + V) END SELECT L00P: LOOP SELECT CASE O CASE 1, 2 PRINT #2, "" CASE 3 PRINT #2, "end:;" PRINT #2, " return 0;" PRINT #2, "}" CASE 4 PRINT #2, "PROGRAM ENDP" PRINT #2, "M:" CASE 5 PRINT #2, "PROGRAM ENDP" PRINT #2, "END PROGRAM" END SELECT PRINT "Done." CLOSE #1, #2 END EROR: PRINT LTRIM$(STR$(L)); ": "; E$ END GETNUM: N = 0 DO V = ASC(MID$(A$, S, 1)) - 48 IF V < 0 OR V > 9 THEN S = S - 1: EXIT DO N = N * 10 + V: S = S + 1 LOOP N$ = LTRIM$(STR$(N)) RETURN PARSE: SELECT CASE MID$(A$, S, 1) CASE "a" TO "z" X$ = LTRIM$(STR$(ASC(MID$(A$, S, 1)) + 159)) SELECT CASE O CASE 1, 2 PRINT #2, V$ + " = " + X$ + ": "; CASE 3 PRINT #2, " " + LCASE$(V$) + "=m+" + X$ + ";" CASE 4, 5 PRINT #2, " MOV "; PRINT #2, MID$("DS", ASC(V$) - 87, 1) + "I,OFFSET M+" + X$ END SELECT CASE "*" SELECT CASE O CASE 1, 2 PRINT #2, V$ + " = 256 * M(257) + M(256): "; CASE 3 PRINT #2, " " + LCASE$(V$) + "=m+256*m[257]+m[256];" CASE 4, 5 PRINT #2, " MOV "; PRINT #2, MID$("DS", ASC(V$) - 87, 1) + "I,WORD PTR M[256]" END SELECT CASE ELSE GOSUB GETNUM SELECT CASE O CASE 1, 2 PRINT #2, V$ + " = " + N$ + ": "; CASE 3 PRINT #2, " " + LCASE$(V$) + "=m+" + N$ + ";" CASE 4, 5 PRINT #2, " MOV "; PRINT #2, MID$("DS", ASC(V$) - 87, 1) + "I,OFFSET M+" + N$ END SELECT END SELECT S = S + 1 RETURN GTO: IF VAL(N$) = 0 THEN SELECT CASE O CASE 1 PRINT #2, "END"; CASE 2 PRINT #2, "SYSTEM"; CASE 3 PRINT #2, " goto end;"; CASE 4 PRINT #2, " RET" CASE 5 PRINT #2, " MOV AX,4C00h" PRINT #2, " INT 21h" END SELECT ELSE SELECT CASE O CASE 1, 2 PRINT #2, "GOTO " + N$; CASE 3 PRINT #2, " goto l" + N$ + ";"; CASE 4, 5 PRINT #2, " JMP L" + N$ END SELECT END IF RETURN