class: center, middle count: false # Back to the BASICs ## Jan 'half/byte' Krutisch ## Baltic Ruby 2024 --- class: center, middle # Back to the BASICs ## Jan 'half/byte' Krutisch ## Baltic Ruby 2024 --- class: center, middle # Let's go back in time --- class: center, middle, amber # 1985 ??? Age hook, but skip the joke --- class: center, middle, on-image, big background-image: url(img/altair8800.png) # 1975 ??? - Altair 8800 - Microsoft BASIC by Bill Gates, Paul Allen, Monte Davidoff --- background-image: url(img/altair_basic_better.jpg) --- # First wave of home computers - Apple II (1977) - Commodore PET, VIC-20, C-64 ('77, '80, '82) - TRS-80 (1977 / 1980) - Atari 400/800 (1979) - Sinclair ZX80, ZX81, Spectrum (1980, '81, '82) - Acorn BBC Micro (1981) - Amstrad CPC (1984) - ... --- class: center, middle # Why I like these systems --- class: center, middle # Simple --- class: center, middle # Complete understanding --- class: center, middle, big, on-image background-image: url(img/amiga.png) # 1985 --- class: center, middle, big, on-image background-image: url(img/c64.png) # Commodore C64 ??? Also came with Microsoft BASIC --- class: green, big, center, middle # BASIC --- ## Beginners ## All purpose ## Symbolic ## Instruction ## Code --- class: center, middle # Some BASIC facts ??? - created in 1963 at Dartmouth College (NH) - by John G. Kemeny & Thomas E. Kurtz - Originally a compiled language for multi-user systems - Later: Interpreter for smaller computers - Micro-Soft BASIC for home computers (Written by Bill Gates, Paul Allen and Monte Davidoff) - Most home computers use some variant of MS BASIC --- background-image: url(img/c64_basic.png) --- # A BASIC example ```basic 10 FOR I = 1 TO 200 STEP 0.2 20 GOSUB 100 30 PRINT SPC(II);"#" 40 NEXT I 50 END 100 II = INT((SIN(I) + 1)*20) 110 RETURN ``` --- # What stands out ```basic 10 FOR I = 1 TO 200 STEP 0.2 20 GOSUB 100 30 PRINT SPC(II);"#" 40 NEXT I 50 END 100 II = INT((SIN(I) + 1)*20) 110 RETURN ``` --- # BASIC IS LOUD!!!1!! ```basic 10 FOR I = 1 TO 200 STEP 0.2 20 GOSUB 100 30 PRINT SPC(II);"#" 40 NEXT I 50 END 100 II = INT((SIN(I) + 1)*20) 110 RETURN ``` --- # Short variable names ```basic 10 FOR I = 1 TO 200 STEP 0.2 20 GOSUB 100 30 PRINT SPC(II);"#" 40 NEXT I 50 END 100 II = INT((SIN(I) + 1)*20) 110 RETURN ``` --- # All Variables are global ```basic 10 FOR I = 1 TO 200 STEP 0.2 20 GOSUB 100 30 PRINT SPC(II);"#" 40 NEXT I 50 END 100 II = INT((SIN(I) + 1)*20) 110 RETURN ``` --- # No "functions", no args ```basic 10 FOR I = 1 TO 200 STEP 0.2 20 GOSUB 100 30 PRINT SPC(II);"#" 40 NEXT I 50 END 100 II = INT((SIN(I) + 1)*20) 110 RETURN ``` --- # Explicit line numbers ```basic 10 FOR I = 1 TO 200 STEP 0.2 20 GOSUB 100 30 PRINT SPC(II);"#" 40 NEXT I 50 END 100 II = INT((SIN(I) + 1)*20) 110 RETURN ``` --- background-image: url(img/teletype.png) --- class: video, middle, center
--- class: middle, center ![](img/basic_in_mem.drawio.png) ??? - zero as delimiter - pointer to next line - line number - token --- class: middle, center, amber # Modern development workflow --- class: middle, center, green # Let's find out what's going on --- background-image: url(img/c64_insider_book.png) ??? A book from 1988 --- background-image: url(img/lee_davison_commentary.png) --- background-image: url(img/pagetable.png) --- class: center, middle # Behold: 6502 assembler --- class: center, middle # Don't be afraid --- class: center, middle # First part of # "BASIC warm start" ## (MAIN:) --- # BASIC warm start
the warm start vector is initialised to point here
A483
20 60 A5
JSR
$A560
call for BASIC input
A486
86 7A
STX $7A
save BASIC execute pointer low byte
A488
84 7B
STY $7B
save BASIC execute pointer high byte
A48A
20 73 00
JSR $0073
increment and scan memory
A48D
AA
TAX
copy byte to set flags
A48E
F0 F0
BEQ
$A480
loop if no input
got to interpret the input line now ....
A490
A2 FF
LDX #$FF
current line high byte to -1, indicates immediate mode
A492
86 3A
STX $3A
set current line number high byte
A494
90 06
BCC
$A49C
if numeric character go handle new BASIC line
no line number .. immediate mode
A496
20 79 A5
JSR
$A579
crunch keywords into BASIC tokens
A499
4C E1 A7
JMP
$A7E1
go scan and interpret code
--- class: middle, center # .opcode[JSR] .arg[$A560] ## Jump to SubRoutine ### Push return address on stack --- class: middle, center # What does .arg[$A560] do? ## Waits for input ## X, Y contain buffer address ## Ends with .opcode[RTS] --- class: middle, center # .opcode[RTS] ## ReTurn from Subroutine ## Pops return address on stack --- class: middle, center # What's X and Y? --- class: center # Registers .contain[![](img/registers.drawio.png)] --- class: middle, center # .opcode[STX] .arg[$7A] # .opcode[STY] .arg[$7B] ## SToreX, SToreY ### stores register in memory --- class: middle, center # Odd address much? --- class: middle, center # Zeropage --- class: middle, center # .opcode[JSR] .arg[$0073] ### jumps to CHRGET --- class: middle, center # CHRGET? ### increments pointers in .arg[$7A], .arg[$7B] ### reads character there into A ### Sets a couple of flags --- class: middle, center # .opcode[TAX] ## Transfer A to X --- class: middle, center # .opcode[BEQ] .arg[$A480] ## Branch if EQual ### If zero flag is set, branch to relative address ### (Actual byte code: .bytes[F0 F0]) ### .bytes[FO] = -16 --- class: middle, center # Yeah, but, why? ## If read byte is zero: ## line was empty, so restart --- class: middle, center # .opcode[LDX] .arg[\#$FF] ## LoaDX ### Load immediate value into X ### X = -1 --- class: middle, center # .opcode[STX] .arg[$3A] ### .arg[$3A] is current BASIC line number ### -1 signifies immediate mode --- class: middle, center # .opcode[BCC] .arg[$A49C] ## Branch if Carry Clear ### Carry flag usually for arithmetic operations ??? CHRGET sets carry if not a digit character --- class: middle, center # .opcode[JSR] .arg[$A579] ### Jump to tokenizer (CRUNCH) --- class: middle, center # .opcode[JMP] .arg[$A7E1] ## JuMP ### (No address pushed on stack) --- class: middle, center # .arg[$A7E1] is interpreter start point --- class: middle, center # Let's turn it into Ruby --- ```ruby loop do begin line = @input.readline.strip parse(line) rescue BasicError => e @error.puts e.message @output.puts "READY." end end def parse(line) if line[0] =~ /\d/ parse_line(line) else parse_direct(line) end end ``` --- class: middle, center, green # A few core concepts --- class: middle, center # Tokenizer ## CRUNCH: --- # Find token (pseudocode) ```ruby buffer = input pos = 0 # position in pointer token = 0 n = 0 loop do if token[i][n] == buffer[pos + n] token += 1 n = 0 else return token end end ``` --- class: middle, center # ! TRUTH / 2 ??? Not even half the truth --- class: middle, center # Interpreter ## NEWSTT: --- # Interpreter 1. look for token 2. lookup routine in table 3. call routine 4. rinse, repeat --- # Let's PRINT ```basic 10 PRINT (2 + 2) * 5 + SIN(XY) ``` --- class: middle, center # What shall we PRINT? --- class: middle, center # Formula Evaluation ## FRMEVL:, EVAL: --- # Expression evaluation ```ruby (2 + 2) * 5 + SIN(XY) ``` --- class: video, middle, center
--- class: middle, center, amber # This nearly broke me --- class: middle, center, green, big # Ruby BASIC? --- class: middle, center # Roughly 1000-1500 lines ## (Of terrible ruby code) ## codeberg.org/halfbyte/ruby-basic --- class: middle, center # DEMO --- class: video, middle, center
--- class: green, middle, center # What did I learn --- class: middle, center # Microsoft BASIC # is # a work of art --- class: middle, center # A very different world --- class: middle, center # Hard to transfer to Ruby ## (sometimes) --- class: middle, center # Global State is good, actually --- class: middle, center # Global State is good, actually ## (sometimes) --- class: green, big, center, middle # Complexity --- class: center, middle # What are we doing? --- background-image: url(img/book_stack.png) --- class: center, middle # So many CPU cycles lost --- class: center, middle # So much Energy spent --- class: center, middle, amber ## cough, LLMs, cough --- class: center, middle ## I don't want to go back --- class: center, middle ## BUT: Be more aware? --- class: center, middle ## What is your impact? --- class: center, middle ## What are the incentives? --- class: center, middle ## At least: Don't pile on --- class: green, center, middle # Acknowledgements --- # Michael Steil # Lee Davison # The VICE team # My Betatesters ## (aka RubyUnconf) --- class: center # Jan Krutisch ## Co-Founder of Depfu.com ## Freelance Web Developer ## Digital Artist ## Looking for work ## @halfbyte@ruby.social ## https://halfbyte.me # Thank you!