An ECMA-55 Minimal BASIC Compiler for x86-64 Linux®
Abstract
:1. Introduction
- (1)
- Serve as a standards-compliant baseline compiler implementation for the classic ECMA-55 Minimal BASIC dialect that can be used on x86-64 Linux®.
- (2)
- Serve as an example compiler for entry-level undergraduate compiler courses at institutions where the students may possess only modest programming and algorithmic skill.
2. Experimental Section
2.1. Which Standard To Implement?
2.2. Target Language
2.3. Debugging Machine Code on x86-64 Linux®
2.4. Compiler Structure
2.4.1. Line Number Module
2.4.2. Scanner Module
2.4.3. Types Of Variables
2.4.4. Parser Module
2.4.5. Numeric Support With Exceptions
2.4.6. Symbol Table Module
2.4.7. Code Generation Module
2.4.7.1. Examining The Actual Translation
2.4.7.2. Arithmetic Expression Evaluation
10 LET A=4 20 LET B=3 30 PRINT A/B+2/3 40 END
1127 .LLINE0030: 1128 movabsq $.LCURLINENO, %rax 1129 movq $30, (%rax) 1130 floatmem_to_floatreg A,%xmm0,’A’ 1131 pushxmm 0 1132 floatmem_to_floatreg B,%xmm0,’B’ 1133 pushxmm 0 1134 binary_divide 1135 floatlit_to_floatreg .LFLIT0002,%xmm0,2 1136 pushxmm 0 1137 floatlit_to_floatreg .LFLIT0001,%xmm0,3 1138 pushxmm 0 1139 binary_divide 1140 binary_add 1141 popxmm 0 1142 movabsq $printfloat, %rax 1143 callq *%rax 1144 movabsq $outputbuf, %rax 1145 callq *%raxIdeally the compiler would compute the value of 2/3 and avoid emitting the division for that part of the expression, but this non-optimizing compiler does not implement constant folding.
2.4.7.3. IF Statement
10 INPUT X 20 IF X>50 THEN 50 30 PRINT "NOT MORE THAN 50" 40 GOTO 60 50 PRINT "MORE THAN 50" 60 END
1175 .LLINE0020: 1176 movabsq $.LCURLINENO, %rax 1177 movq $20, (%rax) 1178 floatmem_to_floatreg X,%xmm0,’X’ 1179 pushxmm 0 1180 floatlit_to_floatreg .LFLIT0000,%xmm0,50 1181 pushxmm 0 1182 popxmm 1 # rhs expression value 1183 popxmm 0 # lhs expression value 1184 comisd %xmm1, %xmm0 1185 jp 0f # LHS and/or RHS was NaN 1186 jbe 1f 1187 movabsq $.LLINE0050,%rax 1188 jmpq *%rax 1189 0: 1190 movabsq $.Luninitialized,%rax 1191 jmpq *%rax 1192 1:
2.4.7.4. FOR and NEXT Statements
10 FOR I=1 TO 10 STEP 2 20 PRINT I 30 NEXT I 40 ENDThe generated assembly code for line 10 is:
1113 .LLINE0010: 1114 movabsq $.LCURLINENO, %rax 1115 movq $10, (%rax) 1116 # compute expression and push custom FOR loop with index I start value 1117 floatlit_to_floatreg .LFLIT0000,%xmm0,1 1118 pushxmm 0 1119 # compute expression and push custom FOR loop with index I limit value 1120 floatlit_to_floatreg .LFLIT0001,%xmm0,10 1121 pushxmm 0 1122 # compute expression and push custom FOR loop with index I increment value 1123 floatlit_to_floatreg .LFLIT0002,%xmm0,2 1124 pushxmm 0 1125 beginfor I,.LFORINCREMENT0000,.LFORLIMIT0000,.LFORTEST0000,.LFORDONE0000
1136 .LLINE0030: 1137 movabsq $.LCURLINENO, %rax 1138 movq $30, (%rax) 1139 endfor I,.LFORINCREMENT0000,.LFORTEST0000,.LFORDONE0000
243 .macro beginfor ndex_var:req,inc_var:req,limit_var:req,tst_lbl:req,done_lbl:req 244 245 .section .rodata,"a",@progbits 246 247 .type .Lbeginfor\@_msg, %object 248 .Lbeginfor\@_msg: 249 .asciz "\ndex_var\()" 250 .size .Lbeginfor\@_msg, .-.Lbeginfor\@_msg 251 252 .section .text,"ax",@progbits 253 254 popxmm 0 255 comisd %xmm0, %xmm0 256 jnp 0f 257 # referenced scalar \inc_var\() was NaN, uninitialized 258 movabsq $.Luninitialized_forinc_msg, %rsi 259 movabsq $printstring, %rax 260 callq *%rax 261 movabsq $badxit, %rax 262 jmpq *%rax 263 0: 264 movabsq $\inc_var\(), %rax 265 movsd %xmm0, (%rax) # store FOR loop with index \ndex_var\() increment value 266 # \inc_var\() 267 popxmm 1 268 comisd %xmm1, %xmm1 269 jnp 1f 270 # referenced scalar \limit_var\() was NaN, uninitialized 271 movabsq $.Luninitialized_forlimit_msg, %rsi 272 movabsq $printstring, %rax 273 callq *%rax 274 movabsq $badxit, %rax 275 jmpq *%rax 276 1: 277 movabsq $\limit_var\(), %rax 278 movsd %xmm1, (%rax) # store FOR loop with index \ndex_var\() limit value in 279 # \limit_var\() 280 popxmm 2 281 comisd %xmm2, %xmm2 282 jnp 2f 283 # referenced scalar \ndex_var\() was NaN, uninitialized 284 movabsq $.Luninitialized_forindex_msg, %rsi 285 movabsq $printstring, %rax 286 callq *%rax 287 movabsq $.Lbeginfor\@_msg, %rsi 288 movabsq $printstring, %rax 289 callq *%rax 290 movabsq $badxit, %rax 291 jmpq *%rax 292 2: 293 movabsq $\ndex_var\(), %rax 294 movsd %xmm2, (%rax) # store FOR loop index var \ndex_var\() initial value 295 \tst_lbl\(): # FOR loop with index var \ndex_var\() test code starts here 296 pxor %xmm3,%xmm3 # xmm3=0 297 movabsq $\ndex_var\(), %rax 298 movsd (%rax),%xmm0 # xmm0=\ndex_var\() (FOR loop index variable) 299 comisd %xmm0, %xmm0 300 jnp 3f 301 # referenced scalar \ndex_var\() was NaN, uninitialized 302 movabsq $.Luninitialized_forindex_msg, %rsi 303 movabsq $printstring, %rax 304 callq *%rax 305 movabsq $.Lbeginfor\@_msg, %rsi 306 movabsq $printstring, %rax 307 callq *%rax 308 movabsq $badxit, %rax 309 jmpq *%rax 310 3: 311 movabsq $\limit_var\(), %rax 312 movsd (%rax),%xmm1 # xmm1=\limit_var\() (FOR loop with index \ndex_var\() 313 # limit value) 314 comisd %xmm1, %xmm1 315 jnp 4f 316 # referenced scalar \limit_var\() was NaN, uninitialized 317 movabsq $.Luninitialized_forlimit_msg, %rsi 318 movabsq $printstring, %rax 319 callq *%rax 320 movabsq $badxit, %rax 321 jmpq *%rax 322 4: 323 subsd %xmm1,%xmm0 324 # xmm0=\ndex_var\()-\limit_var\() (FOR loop index var \ndex_var\() 325 # FOR loop with index \ndex_var\() limit val) 326 movabsq $\inc_var\(), %rax 327 movsd (%rax),%xmm2 # xmm2=\inc_var\() (FOR loop with index \ndex_var\() 328 # increment value) 329 ucomisd %xmm3,%xmm2 330 jae 5f # if FOR loop with index \ndex_var\() increment \inc_var\() 331 # is non-negative then goto 0 (positive increment) 332 # else (negative increment) 333 movabsq $.LFLT_NEG_MASK, %r15 334 movsd (%r15), %xmm1 335 pxor %xmm1, %xmm0 # xmm0=(-xmm0) 336 5: 337 ucomisd %xmm3,%xmm0 338 # IF (FORINDEX-FORLIMIT)*SGN(FORINCREMENT)<=0 THEN 339 # GOTO FORLOOPBODY 340 jbe 6f # if ABS(\ndex_var\()-\limit_var\()) <=0 then goto 1 341 # (FOR loop with index \ndex_var\() body) 342 movabsq $\done_lbl\(), %rax 343 jmpq *%rax # else goto \done_lbl\() (exit FOR loop with 344 # index var \ndex_var\()) 345 # FOR loop with index var \ndex_var\() test code ends here 346 6: # FOR loop with index var \ndex_var\() body begins here 347 .endm 348 349 .macro endfor ndex_var:req,inc_var:req,tst_lbl:req,done_lbl:req 350 351 .section .rodata,"a",@progbits 352 353 .type .Lendfor\@_msg, %object 354 .Lendfor\@_msg: 355 .asciz "\ndex_var\()" 356 .size .Lendfor\@_msg, .-.Lendfor\@_msg 357 358 .section .text,"ax",@progbits 359 360 # FOR loop with index var \ndex_var\() body ends here 361 # FOR loop with index var \ndex_var\() increment starts here 362 movabsq $\ndex_var\(), %rax 363 movsd (%rax),%xmm0 364 comisd %xmm0, %xmm0 365 jnp 1f 366 # referenced scalar \ndex_var\() was NaN, uninitialized 367 movabsq $.Luninitialized_forindex_msg, %rsi 368 movabsq $printstring, %rax 369 callq *%rax 370 movabsq $.Lendfor\@_msg, %rsi 371 movabsq $printstring, %rax 372 callq *%rax 373 movabsq $badxit, %rax 374 jmpq *%rax 375 1: 376 pushxmm 0 # push FOR loop index variable \ndex_var\() 377 movabsq $\inc_var\(), %rax 378 movsd (%rax),%xmm0 379 comisd %xmm0, %xmm0 380 jnp 2f 381 # referenced scalar \inc_var\() was NaN, uninitialized 382 movabsq $.Luninitialized_forinc_msg, %rsi 383 movabsq $printstring, %rax 384 callq *%rax 385 movabsq $badxit, %rax 386 jmpq *%rax 387 2: 388 pushxmm 0 # push FOR loop with index \inc_var\() 389 # increment variable \ndex_var\() 390 binary_add 391 popxmm 0 392 # increment FOR loop index variable \ndex_var\() 393 movabsq $\ndex_var\(), %rax # \ndex_var\() = \ndex_var\() + \inc_var\() 394 movsd %xmm0,(%rax) 395 # FOR loop with index var \ndex_var\() increment ends here 396 movabsq $\tst_lbl\(), %rax 397 jmpq *%rax # goto FOR loop with index var \ndex_var\() 398 # test label \tst_lbl\() 399 \done_lbl\(): 400 movabsq $\inc_var\(), %rax 401 movabsq $SNaN,%r15 402 movq %r15,(%rax) # \inc_var\() is now uninitialized again so 403 # illegal jumps into the FOR loop with index var 404 # \ndex_var\() can be detected. 405 .endm
10 FOR I=1 TO 10 STEP 2 20 FOR J=20 TO 5 STEP -5 30 NEXT I 40 NEXT J
2.4.7.5. GOTO Statement
10 GOTO 30 20 PRINT "NEVER HERE" 30 PRINT "DONE" 40 ENDThe corresponding assembly code for line 10 follows:
1113 .LLINE0010: 1114 movabsq $.LCURLINENO, %rax 1115 movq $10, (%rax) 1116 movabsq $.LLINE0030, %rax 1117 jmpq *%raxLines 1116 and 1117 implement the GOTO using a register indirect jump as required for x86-64 large mode code.
2.4.7.6. ON .. GOTO Statement
10 INPUT X 20 ON X GOTO 100,200,300 30 PRINT "UNREACHABLE" 40 STOP 100 PRINT "CHOICE 1" 110 GOTO 40 200 PRINT "CHOICE 2" 210 GOTO 40 300 PRINT "CHOICE 3" 310 GOTO 40 400 ENDThe corresponding assembly code for line 20 after passing through the peephole optimizer follows:
1175 .LLINE0020: 1176 movabsq $.LCURLINENO, %rax 1177 movq $20, (%rax) 1178 floatmem_to_floatreg X,%xmm0,’X’ 1179 cvtsd2sil %xmm0, %eax 1180 stmxcsr .Lnewmxcsr 1181 testl $FE_INVALID,.Lnewmxcsr 1182 jz 0f 1183 jmp 1f 1184 0: 1185 decl %eax 1186 cmpl $2,%eax 1187 ja 1f 1188 jmp *.LJT0000(,%rax,8) 1189 1: 1190 movabsq $.Longotofail_msg, %rsi 1191 movabsq $.Lprint_error_message, %rax 1192 jmpq *%rax 1193 1194 .section .rodata,"a",@progbits 1195 1196 .LJT0000: 1197 .quad .LLINE0100 1198 .quad .LLINE0200 1199 .quad .LLINE0300 1200 1201 .section .text,"ax",@progbits
2.4.7.7. GOSUB and RETURN Statements
10 LET A=5 20 LET B=10 30 GOSUB 60 40 PRINT C 50 STOP 60 LET C=A+B 70 RETURN 80 ENDHere is the code for the GOSUB 60 on line 30:
1127 .LLINE0030: 1128 movabsq $.LCURLINENO, %rax 1129 movq $30, (%rax) 1130 gosub 0f .LLINE0060 1131 0:
1157 .LLINE0070: 1158 movabsq $.LCURLINENO, %rax 1159 movq $70, (%rax) 1160 return
2.4.7.8. DEF Statement
10 DEF FNA(Y)=Y*Y*Y 20 PRINT FNA(1024) 30 ENDHere is the code used on line 20 to call FNA with an argument of 1024 and display the answer (after the peephole optimization):
1116 .LLINE0020: 1117 movabsq $.LCURLINENO, %rax 1118 movq $20, (%rax) 1119 floatlit_to_floatreg .LFLIT0000,%xmm0,1024 1120 movabsq $FNA,%rax 1121 callq *%rax 1122 movabsq $printfloat, %rax 1123 callq *%rax 1124 movabsq $outputbuf, %rax 1125 callq *%rax
6618 .section .data,"aw",@progbits 6619 6620 .LFNA_Y: 6621 .quad SNaN # 8 bytes, actually double 6622 .size .LFNA_Y, .-.LFNA_Y 6623 6624 .section .text,"ax",@progbits 6625 6626 .type FNA, @function 6627 FNA: 6628 pushq %rbp 6629 movq %rsp, %rbp 6630 movabsq $.LFNA_Y, %r15 6631 movsd %xmm0, (%r15) # store function argument Y 6632 floatmem_to_floatreg .LFNA_Y,%xmm0,’Y’ 6633 pushxmm 0 6634 floatmem_to_floatreg .LFNA_Y,%xmm0,’Y’ 6635 pushxmm 0 6636 binary_multiply 6637 floatmem_to_floatreg .LFNA_Y,%xmm0,’Y’ 6638 pushxmm 0 6639 binary_multiply 6640 popxmm 0 # pop stack into xmm0 for return 6641 movq %rbp,%rsp 6642 popq %rbp 6643 retq 6644 .size FNA, .-FNA
2.4.7.9. Arrays
10 LET A(1)=9 20 LET A(A(1)-7)=A(1)*2 30 PRINT A(2) 40 ENDThe generated assembly code for line 20 after passing through the peephole optimizer is:
1123 .LLINE0020: 1124 movabsq $.LCURLINENO, %rax 1125 movq $20, (%rax) 1126 floatlit_to_floatreg .LFLIT0000,%xmm0,1 1127 array_1D_to_floatreg A,%xmm0,’A’,0,10,%r8,%r15 1128 pushxmm 0 1129 floatlit_to_floatreg .LFLIT0002,%xmm0,7 1130 pushxmm 0 1131 binary_subtract 1132 floatlit_to_floatreg .LFLIT0000,%xmm0,1 1133 array_1D_to_floatreg A,%xmm0,’A’,0,10,%r8,%r15 1134 pushxmm 0 1135 floatlit_to_floatreg .LFLIT0003,%xmm0,2 1136 pushxmm 0 1137 binary_multiply 1138 popxmm 2 # RHS expression value 1139 popxmm 0 # array index expression value 1140 floatreg_to_array_1D A,%xmm2,%xmm0,0,10,%r8,%r15
10 OPTION BASE 1 20 LET A(1,1)=9 30 PRINT A(1,1) 40 END
1129 .LLINE0030: 1130 movabsq $.LCURLINENO, %rax 1131 movq $30, (%rax) 1132 floatlit_to_floatreg .LFLIT0000,%xmm0,1 1133 pushxmm 0 1134 floatlit_to_floatreg .LFLIT0000,%xmm0,1 1135 pushxmm 0 1136 popxmm 1 # column index 1137 popxmm 0 # row index 1138 array_2D_to_floatreg A,%xmm0,%xmm1,’A’,1,10,10,%r8,%r9,%r15 1139 pushxmm 0 1140 popxmm 0 1141 movabsq $printfloat, %rax 1142 callq *%rax 1143 movabsq $outputbuf, %rax 1144 callq *%rax
2.4.7.10. Strings
5 LET S$="HELLO" 10 PRINT S$
1113 .LLINE0005: 1114 movabsq $.LCURLINENO, %rax 1115 movq $5, (%rax) 1116 movabsq $.LSLIT0000, %rdi # %rdi=pointer to ’HELLO’ 1117 pushsaddr 1118 popsaddr %rsi 1119 movq %rsi,%rdi 1120 movabsq $mystrlen, %rax 1121 callq *%rax 1122 cmpq $MAX_STRING_BYTES,%rax 1123 jbe 0f 1124 movabsq $.Lstring_too_long,%rax 1125 jmpq *%rax 1126 0: 1127 movabsq $S$, %rdi 1128 movabsq $mystrcpy, %rax 1129 callq *%rax 1130 .LLINE0010: 1131 movabsq $.LCURLINENO, %rax 1132 movq $10, (%rax) 1133 movabsq $S$, %rdi 1134 cmpb $NAK,(%rdi) 1135 jne 0f 1136 # referenced scalar was uninitialized 1137 movabsq $.Luninitialized_msg, %rsi 1138 movabsq $printstring, %rax 1139 callq *%rax 1140 # must create string in reverse order 1141 xorq %rdi,%rdi 1142 movb $’$’,%dil 1143 shl $8,%rdi 1144 movb $’S’,%dil 1145 shl $8,%rdi 1146 movb $32,%dil 1147 movabsq $printvarname,%rax 1148 callq *%rax 1149 movabsq $badxit, %rax 1150 jmpq *%rax 1151 0: 1152 pushsaddr 1153 popsaddr %rdi 1154 movabsq $appendbuf, %rax 1155 callq *%rax 1156 movabsq $outputbuf, %rax 1157 callq *%rax
2.4.7.11. INPUT Statement
- (1)
- number (integer or real)
- (2)
- quoted string
- (3)
- unquoted string
- (4)
- comma
- (5)
- end-of-line (newline)
- (1)
- Initialize the format string to the empty string and open two temporary files.
- (2)
- For each variable in the INPUT statement do:
- (a)
- For numeric variables, emit to the first temporary file code that converts the ASCIIZ holding area string for this numeric item to a floating point representation and stores that back to the temporary holding area, and if an overflow occurs during the conversion, then the code must jump back to the start of the statement. Append an ’N’ to the format string. Emit to the second temporary file code that copies the floating point value from the temporary holding area to the actual variable.
- (b)
- For string variables, append an ’S’ to the format string. Emit to the second temporary file code that copies the ASCIIZ string value from the temporary holding area to the actual variable.
- (3)
- Add the format string to the string literals list in the symbol table so that it will be emitted together with other string literals after the parsing is finished.
- (4)
- Emit code to the main output file to call a function to print a prompt the user for input, do the line input to a buffer, and process that buffer, performing the scan into tokens left to right. As each number or string token is encountered, if the type is compatible, the data is moved to a hidden temporary storage area. Any time an error occurs, the code must jump back to the start of the statement. The code in this phase verifies the type of each item matches the required type from the format string created earlier. The assembly language routine that does all of this is called doinput, and it will reset the input stack pointer itself before processing input. It will also verify that the number of items input by the user matches the required number of variables, and if it does not, then it will force a jump back to the start of the statement. This check is possible by using the length of the ASCIIZ format string, since there is one byte for each variable.
- (5)
- Rewind both temporary files.
- (6)
- Append contents of the first temporary file to the main output file.
- (7)
- Append contents of the second temporary file to the main output file.
- (8)
- Close and remove both temporary files.
10 INPUT A,B$,C(1)
1128 .LLINE0010: 1129 movabsq $.LCURLINENO, %rax 1130 movq $10, (%rax) 1131 movabsq $.LNFMT0010, %rdi 1132 movabsq $doinput, %rax 1133 callq *%rax 1134 # scalar numeric INPUT A (convert, check for overflow, save in temp slot) 1135 movabsq $.Lrt_nput_stack, %r15 1136 movabsq $0,%rax # slot number 0 on .Lrt_nput_stack 1137 movabsq $38,%r9 # width of a record on .Lrt_nput_stack 1138 mulq %r9 1139 leaq 1(%r15,%rax),%rdi # 1st arg is ASCIZ buffer 1140 xorl %esi, %esi # 2nd arg is NULL 1141 movabsq $strtod, %rax # call code to do actual conversion from ASCIIZ to floating point 1142 callq *%rax 1143 movsd %xmm0, %xmm1 1144 # if xmm1 is +Infinity then overflow 1145 movabsq $PInf,%r13 # move constant +INF into r13 1146 subq $8,%rsp # allocate scratch 8 byte area 1147 # it is a union location for 1148 # converting between 64 bit double and 1149 # unsigned 64 int 1150 movq %r13 ,(%rsp) # temp = +INF 1151 movsd (%rsp),%xmm0 # move +INF into xmm0 1152 addq $8,%rsp # deallocate scratch 8 byte area 1153 comisd %xmm1,%xmm0 1154 jne 0f 1155 # got overflow 1156 movabsq $.Loverflow_msg,%rsi 1157 movabsq $exception_non_fatal,%r13 1158 callq *%r13 1159 movabsq $.LLINE0010,%rax 1160 jmpq *%rax 1161 0: 1162 movabsq $.Lrt_nput_stack, %r15 1163 movabsq $0, %rax 1164 movabsq $38, %r9 1165 mulq %r9 1166 movsd %xmm1,1(%r15,%rax) 1167 # scalar string INPUT B$ (do nothing right now, already in temp slot) 1168 # array numeric INPUT C (convert, check for overflow, save in temp slot) 1169 movabsq $.Lrt_nput_stack, %r15 1170 movabsq $2,%rax # slot number 2 on .Lrt_nput_stack 1171 movabsq $38,%r9 # width of a record on .Lrt_nput_stack 1172 mulq %r9 1173 leaq 1 (%r15,%rax),%rdi # 1st arg is ASCIZ buffer 1174 xorl %esi, %esi # 2nd arg is NULL 1175 movabsq $strtod, %rax # call code to do actual conversion from ASCIIZ to floating point 1176 callq *%rax 1177 movsd %xmm0, %xmm1 1178 # if xmm1 is +Infinity then overflow 1179 movabsq $PInf,%r13 # move constant +INF into r13 1180 subq $8,%rsp # allocate scratch 8 byte area 1181 # it is a union location for 1182 # converting between 64 bit double and 1183 # unsigned 64 int 1184 movq %r13 ,(%rsp) # temp = +INF 1185 movsd (%rsp),%xmm0 # move +INF into xmm0 1186 addq $8,%rsp # deallocate scratch 8 byte area 1187 comisd %xmm1,%xmm0 1188 jne 0f 1189 # got overflow 1190 movabsq $.Loverflow_msg,%rsi 1191 movabsq $exception_non_fatal,%r13 1192 callq *%r13 1193 movabsq $.LLINE0010,%rax 1194 jmpq *%rax 1195 0: 1196 movabsq $.Lrt_nput_stack, %r15 1197 movabsq $2, %rax 1198 movabsq $38, %r9 1199 mulq %r9 1200 movsd %xmm1,1(%r15,%rax) 1201 1202 # INPUT ok, copy from temp locations to real locations 1203 1204 # scalar numeric INPUT A phase 2 1205 movabsq $.Lrt_nput_stack, %r15 1206 movsd 1(%r15),%xmm1 1207 movabsq $A, %r14 1208 movsd %xmm1, (%r14) 1209 # scalar string INPUT B$ phase 2 1210 movabsq $.Lrt_nput_stack, %r15 1211 movabsq $38, %rax 1212 leaq 1(%r15,%rax),%rsi # 2nd arg is source 1213 movabsq $B$, %rdi # 1st arg is destination 1214 movabsq $mystrcpy, %rax 1215 callq *%rax 1216 floatlit_to_floatreg .LFLIT0000,%xmm0,1 1217 pushxmm 0 1218 # array numeric INPUT C phase 2 1219 movabsq $.Lrt_nput_stack, %r15 1220 movabsq $38, %r9 1221 movabsq $2, %rax 1222 mulq %r9 1223 movsd 1(%r15,%rax),%xmm1 1224 pushxmm 1 1225 popxmm 2 # RHS expression value 1226 popxmm 0 # array index expression value 1227 floatreg_to_array_1D C,%xmm2,%xmm0,0,10,%r8,%r15
2.4.7.12. PRINT Statement
10 LET P=1.234 20 LET Q$="DEMO" 30 PRINT "00000000011111111112" 40 PRINT "12345678901234567890" 50 PRINT "P is";P,Q$;TAB(5);"FIVE" 60 ENDHere is the actual output when this program is run:
00000000011111111112 12345678901234567890 P is 1.234 DEMO FIVE
1151 .LLINE0050: 1152 movabsq $.LCURLINENO, %rax 1153 movq $50, (%rax) 1154 movabsq $.LSLIT0003, %rdi # %rdi=pointer to ’P is’ 1155 movabsq $appendbuf, %rax 1156 callq *%rax 1157 floatmem_to_floatreg P,%xmm0,’P’ 1158 movabsq $printfloat, %rax 1159 callq *%rax 1160 movabsq $nextzone, %rax 1161 callq *%rax 1162 movabsq $Q$, %rdi 1163 cmpb $NAK,(%rdi) 1164 jne 0f 1165 # referenced scalar was uninitialized 1166 movabsq $.Luninitialized_msg, %rsi 1167 movabsq $printstring, %rax 1168 callq *%rax 1169 # must create string in reverse order 1170 xorq %rdi,%rdi 1171 movb $’$’,%dil 1172 shl $8,%rdi 1173 movb $’Q’,%dil 1174 shl $8,%rdi 1175 movb $32,%dil 1176 movabsq $printvarname,%rax 1177 callq *%rax 1178 movabsq $badxit, %rax 1179 jmpq *%rax 1180 0: 1181 movabsq $appendbuf, %rax 1182 callq *%rax 1183 floatlit_to_floatreg .LFLIT0001,%xmm0,5 1184 cvtsd2si %xmm0,%rdi 1185 movabsq $tab, %rax 1186 callq *%rax 1187 movabsq $.LSLIT0004, %rdi # %rdi=pointer to ’FIVE’ 1188 movabsq $appendbuf, %rax 1189 callq *%rax 1190 movabsq $outputbuf, %rax 1191 callq *%rax
2.4.7.13. READ, DATA, and RESTORE Statements
10 DATA 5,"HELLO",1,1,2,"HELLO" 20 READ C 30 FOR I=1 TO C 40 READ S$ 50 PRINT S$ 60 NEXT I 70 RESTORE 80 REM READ IT ALL AT ONCE 90 READ C,A$,B,C,D,E$ 100 PRINT A$,B,C,D,E$ 110 END
1131 .LLINE0020: 1132 movabsq $.LCURLINENO, %rax 1133 movq $20, (%rax) 1134 # scalar numeric READ C 1135 movabsq $.Ldata_item_ptr, %rax 1136 movq (%rax), %rax 1137 movabsq $.Ldata_item_count, %rbx 1138 movq (%rbx), %rbx 1139 cmpq %rbx, %rax 1140 jb 0f 1141 movabsq $.Lout_of_data, %rax 1142 jmpq *%rax 1143 0: 1144 movabsq $.Ldata_items, %rbx # base of data_items array of struct pointers 1145 movq (%rbx,%rax,8),%rax # load pointer value in slot rax 1146 cmpb $2,(%rax) 1147 je 1f 1148 movabsq $.Lbad_number_read, %rax 1149 jmpq *%rax 1150 1: 1151 movsd 1(%rax),%xmm0 # ok, load double 2 bytes into that structure into xmm0 1152 movabsq $C, %rax 1153 movsd %xmm0,(%rax) 1154 movabsq $.Ldata_item_ptr, %rax 1155 incq (%rax) # increment data_item_ptr in memory but not register 1156 movabsq $PInf,%r15 1157 subq $8,%rsp # allocate scratch 8 byte area 1158 # it is a union location for 1159 # converting between 64 bit double and 1160 # unsigned 64 int 1161 movq %r15 ,(%rsp) # temp = +INF 1162 movsd (%rsp),%xmm1 # xmm1 = +INF 1163 ucomisd %xmm1,%xmm0 1164 jne 2f 1165 jmp 3f 1166 2: 1167 movabsq $NInf,%r15 1168 movq %r15 ,(%rsp) # temp = -INF 1169 movsd (%rsp),%xmm1 # xmm1 = -INF 1170 ucomisd %xmm1,%xmm0 1171 jne 4f 1172 3: 1173 # overflow message 1174 movabsq $.Loverflow_msg,%rsi 1175 movabsq $exception_non_fatal,%r15 1176 callq *%r15 1177 4: 1178 addq $8,%rsp # deallocate scratch 8 byte area
7220 .align 16 7221 .type .Ldata_items, @object 7222 .Ldata_items: 7223 .quad .LDATA0000 7224 .quad .LDATA0001 7225 .quad .LDATA0002 7226 .quad .LDATA0002 7227 .quad .LDATA0003 7228 .quad .LDATA0001 7229 .size .Ldata_items, .-.Ldata_itemsOn line 7226 which corresponds to the second numeric value 1, it uses .LDATA0002 so that it points to the data block created for the first instance of the numeric value 1 in the list. Similarly, on line 7228 it uses .LDATA0001 for the second “HELLO”, and that is a pointer to the block created for the first “HELLO” that was the second item in the list as shown on line 7224.
7182 .LDATA0000S: # string represenatation 7183 .asciz "5" 7184 .LDATA0000: 7185 .byte 2 # Type is: UQSTR 7186 .double 5 # numeric representation 7187 .byte 2 # length of ASCIIZ string pointed to by .LDATA0000S including NULL byte 7188 .quad .LDATA0000S # pointer to string representation 7189 .size .LDATA0000, .-.LDATA0000 7190 .type .LDATA0000, @objectThis avoids any need for conversion for numeric data items at runtime for the generated executable. The 2 on line 7185 represents the unquoted string type, which can be read into either a numeric or a string variable. The 2 on line 7187 is the length of the ASCIIZ string representation including the terminating NULL byte.
7191 .LDATA0001S: # string represenatation 7192 .asciz "HELLO" 7193 .LDATA0001: 7194 .byte 0 # Type is: QSTR 7195 .byte 6 # length of ASCIIZ string pointed to by .LDATA0001S including NULL byte 7196 .quad .LDATA0001S # pointer to string representation 7197 .size .LDATA0001, .-.LDATA0001 7198 .type .LDATA0001, @objectThe 0 on line 7194 represents the quoted string type, and the 6 on line 7195 is the length of the ASCIIZ string representation including the terminating NULL byte. Note that for type 0, no floating point version exists, because a quoted string cannot be read into a numeric variable.
2.5. Peephole Optimizer
3. Results and Discussion
3.1. Testing The Compiler
3.2. Late Developments
3.3. Teaching with the MinimalBASIC Compiler
- Add support for AND, OR, and NOT logical operators.
- Adding a WHILE/ENDWHILE loop statement pair.
- Modifying the symbol table, runtime library, and scanner by adding support for longer variable names.
- Adding runtime support, updating symbol table support, and changing the grammar for full string support from ECMA-116.
- Changing the code generator by targeting another operating system using the same CPU, for example Apple®’s OS X®.
- Improving the compiler by replacing linked lists with more scalable alternatives.
3.4. Future Work
3.4.1. Full BASIC
3.4.2. Code Generation Improvements
3.4.3. Adding Debugging Support
3.4.4. Adding AVX Support
4. Conclusions
4.1. Results
- (1)
- This compiler includes a complete runtime library, so the behavior of generated executables remains uniform even if the system libraries are different on different Linux distributions.
- (2)
- The generated executables are statically linked and have no embedded paths, so they can be moved both within a filesystem and between machines and they still work, only requiring a Linux 3.X x86-64 kernel.
- (3)
- This is the only fully-compliant implementation of ECMA-55 Minimal BASIC targeting x86-64 Linux.
- (4)
- This is the the first and only 64 bit version of a fully compliant ECMA-55 Minimal BASIC for any platform.
- (5)
- This compiler generates floating point code with full exception checking, something that gcc, clang/LLVM, pcc, and tcc cannot even optionally do.
4.2. Performance of Generated Executables
4.3. Availability
Acknowledgments
Author Contributions
A. Benchmark Programs
A.1. ECMA-55 Minimal BASIC DUMBSINE.BAS Program Source
10 REM THIS IS A PROGRAM DESIGNED TO BURN A LOT OF CPU 20 REM TO GIVE A ROUGH MEASURE OF RUNTIME PERFORMANCE. 30 REM Z IS ARRAY TO HOLD RESULTS FOR SINE(0.0001) THROUGH SINE(PI/8) 40 REM IN STEPS OF 0.001 FOR 1000 VALUES, PI=3.141592653589793 50 DIM Z(4000) 60 DEF FNP=3.141592653989793 65 FOR K=1 TO 1000 70 FOR X=0.0001 TO FNP/8 STEP .0001 80 LET A=X 90 GOSUB 1000 100 LET Z(1000*X)=R 110 NEXT X 120 REM PRINT RESULTS 130 FOR X=0.0001 TO FNP/8 STEP .0001 140 PRINT "MY SIN(";X;") IS";Z(1000*X);"ACTUAL IS";SIN(X); 141 PRINT "DIFF";ABS(SIN(X)-Z(1000*X)) 150 NEXT X 155 NEXT K 160 STOP 1000 REM THIS IS A SINE SUBROUTINE. 1010 REM THE ANGLE IN RADIANS SHOULD BE IN GLOBAL VARIABLE 1020 REM A, AND THE SIN(A) WILL BE RETURNED IN GLOBAL VARIABLE 1030 REM R. A TAYLOR SERIES EXPANSION WITH 5 TERMS IS USED. 1040 LET R=0 1045 REM S IS SIGN FLAG, AND 0 MEANS SUBTRACT, 1 MEANS ADD 1050 LET S=0 1060 FOR I=1 TO 5 STEP 1 1070 REM T IS ONE TERM 1080 LET T=1 1090 REM N IS THE NUMERATOR A^I 1100 LET N=1 1110 FOR J=1 TO I*2-1 STEP 1 1120 LET N=N*A 1130 NEXT J 1140 REM D IS THE DENOMINATOR I! 1150 LET D=1 1160 FOR J=1 TO I*2-1 STEP 1 1170 LET D=D*J 1180 NEXT J 1190 LET T=N/D 1200 IF S=1 THEN 1240 1210 LET R=R+T 1220 LET S=1 1230 GOTO 1260 1240 LET R=R-T 1250 LET S=0 1260 NEXT I 1270 RETURN 1300 END
A.2. C99 dumbsine.c Program Source
/* gcc -Wall -Wextra -pedantic -std=c99 -D_GNU_SOURCE -O0 \ -m64 -march=core2 -mtune=core2 -frounding-math -mno-recip \ -mcmodel=large -mno-recip -fno-associative-math -fmerge-constants \ -fno-inline -fno-built-in dumbsine.c -o dumbsine -lm -static */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <fenv.h> static double Z[4000], A, D, I, J, K, N, R, S, T, X; static int set_excepts; static double FNP(void) { return 3.1415926535989793; } static void mysin(void) { double temp; R=0.0; S=0.0; I=1.0; while (1) { if (I>5.0) break; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); I=INFINITY; } T=1.0; N=1.0; J=1.0; while (1) { temp=I*2.0; if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } temp=temp-1.0; if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } if (J>temp) break; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); J=INFINITY; } if (set_excepts & FE_UNDERFLOW) { fprintf(stderr,"FE_UNDERFLOW exception\n"); J=0.0; } N=N*A; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); N=(A<0?-INFINITY:INFINITY); } if (set_excepts & FE_UNDERFLOW) { fprintf(stderr,"FE_UNDERFLOW exception\n"); N=0.0; } temp=J+1.0; if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } J=temp; } D=1.0; J=1.0; while (1) { temp=I*2.0; if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } temp=temp-1.0; if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } if (J>temp) break; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); J=INFINITY; } if (set_excepts & FE_UNDERFLOW) { fprintf(stderr,"FE_UNDERFLOW exception\n"); J=0.0; } D=D*J; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); D=(J<0?-INFINITY:INFINITY); } if (set_excepts & FE_UNDERFLOW) { fprintf(stderr,"FE_UNDERFLOW exception\n"); D=0.0; } temp=J+1.0; if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } J=temp; } T=N/D; set_excepts = fetestexcept(FE_INVALID | FE_UNDERFLOW | FE_DIVBYZERO); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_UNDERFLOW) { fprintf(stderr,"FE_UNDERFLOW exception\n"); T=0.0; } if (set_excepts & FE_DIVBYZERO) { fprintf(stderr,"FE_DIVBYZERO exception\n"); goto fail2; } if (S==0) { R=R+T; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); R=INFINITY; } S=1.0; } else { R=R-T; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); R=-INFINITY; } S=0.0; } temp=I+1.0; if (set_excepts & FE_INVALID) goto fail; if (set_excepts FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } I=temp; } return; fail2: fprintf(stderr,"FE_DIVBYZERO exception\n"); goto gameover; fail: fprintf(stderr,"FE_INVALID exception\n"); gameover: abort(); } int main(void) { double temp; //#pragma STDC FENV_ACCESS ON // No support for this on Fedora 20 // initialize global data for (X=0;X<4000;X++) Z[(unsigned int)round(X)]=NAN; A = NAN; D = NAN; I = NAN; J = NAN; K = NAN; N = NAN; R = NAN; S = NAN; T = NAN; X = NAN; set_excepts = 0; feclearexcept(FE_INVALID|FE_OVERFLOW); K=1.0; while (1) { if (K>1000.0) break; X=0.0001; while (1) { temp=FNP(); set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } temp=temp/8.0; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } if (X>FNP()/8.0) break; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); X=INFINITY; } A=X; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); A=(X<0?-INFINITY:INFINITY); } mysin(); Z[(unsigned int)round(1000.0*X)]=R; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); Z[(unsigned int)round(1000.0*X)]=(R<0?-INFINITY:INFINITY); } temp=X+0.0001; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } X=temp; } X=0.0001; while (1) { temp=FNP(); set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } temp=temp/8.0; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } if (X>temp) break; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); X=INFINITY; } printf("MY SIN( %17.15lg ) IS %17.15lg ACTUAL IS %17.15lg", X,Z[(unsigned int)round(1000.0*X)],sin(X)); set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); abort(); } printf(" DIFF %17.15lg\n",fabs(sin(X)-Z[(unsigned int)round(1000.0*X)])); set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); abort(); } temp=X+0.0001; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } X=temp; } temp=K+1.0; set_excepts = fetestexcept(FE_INVALID | FE_OVERFLOW); if (set_excepts & FE_INVALID) goto fail; if (set_excepts & FE_OVERFLOW) { fprintf(stderr,"FE_OVERFLOW exception\n"); temp=INFINITY; } K=temp; } return EXIT_SUCCESS; fail: fprintf(stderr,"FE_INVALID exception\n"); return EXIT_FAILURE; }
Conflicts of Interest
References
- Torvalds, L.; (Maintainer). The Linux® Kernel. Available online: http://www.kernel.org/ (accessed on 24 July 2014).
- BASIC A Manual for BASIC, the elementary algebraic language designed for use with the Dartmouth Time Sharing System, 1964
- Kemeny, J.G.; Kurtz, T.E.; Cochran, D. BASIC A Manual for BASIC, the Elementary Algebraic Language Designed for Use with the Dartmouth Time Sharing System, 4th ed.; Dartmouth College Compoutation Center: Hanover, NH, USA, 1968. [Google Scholar]
- Kurtz, T.E. BASIC. ACM SIGPLAN Not. 1978, 13(8), 103–118. [Google Scholar] [CrossRef]
- Isaacs, G.L. Interdialect Translatability of the BASIC Programming Language; Research and Development Division, American College Testing Program; 1972. [Google Scholar]
- Lientz, B.P. A Comparative Evaluation of Versions of BASIC. Commun. ACM 1976, 19, 175–181. [Google Scholar] [CrossRef]
- Luehrmann, A.W.; Garland, S.J. Graphics in the BASIC language. ACM SIGGRAPH Comput. Graph. 1974, 8, 1–8. [Google Scholar] [CrossRef]
- Anderson, R.E. ANSI BASIC The proposed standard. In Proceedings of the ACM’82 Conference; Association for Computing Machinery: New York, NY, USA, 1982; p. 213. [Google Scholar]
- Kurtz, T.E.; Garland, S.J. Toward standardization of BASIC. ACM SIGCUE Outlook 1971, 5, 221–222. [Google Scholar] [CrossRef]
- Dijkstra, E.W. How do we tell truths that might hurt? In Selected Writings on Computing: A Personal Perspective; Springer-Verlag: New York, USA, 1982; pp. 129–131. [Google Scholar]
- Dijkstra, E.W. The threats to computing science. circulated privately.
- Brin, D. Why Johnny Can’t Code. Salon. Sep. 14, 2006. Available online: http://www.salon.com/2006/09/14/basic_2/ (accessed on 24 July 2014).
- Raji, V. Microsoft™ Small Basic. Available online: http://smallbasic.com/ (acessed on 24 July 2014).
- Larsen, I. BASIC-256. Available online: http://www.basic256.org/ (accessed on 24 July 2014).
- Cugini, J.V.; Bowden, J.S.; Skall, M.W. NBS Minimal BASIC Test Programs—Version 2, User’s Manual, Volume 1—Documentation; Government Printing: Washington, DC, USA, 1980. [Google Scholar]
- Cugini, J.V.; Bowden, J.S.; Skall, M.W. NBS Minimal BASIC Test Programs—Version 2, User’s Manual, Volume 2—Source Listings and Sample Output; Government Printing: Washington, DC, USA, 1980. [Google Scholar]
- Kurtz, T.E. Basic. In History of Programming Languages; ACM: New York, NY, USA, 1981; pp. 515–537. [Google Scholar]
- Liguori, A. GLBCC, The GNU/Liberty Compiler Collection. Available online: http://lbpp.sourceforge.net/ (accessed on 24 July 2014).
- Victor, A. FreeBASIC Programming Language. Available online: http://www.freebasic.net/ (accessed on 24 July 2014).
- Kemeny, J.G.; Kurtz, T.E. TrueBASIC. Available online: http://www.truebasic.com/faq#11 (accessed on 24 July 2014).
- Gundel, C. Liberty BASIC. Available online: http://www.libertybasic.com/faq.html#macOrLinux (accessed on 24 July 2014).
- Laboureur, F.; Harter, T. PureBasic. Available online: http://www.purebasic.com/ (accessed on 24 July 2014).
- Intel® Extended Memory 64 Technology Software Developer’s Guide, Revision 1.1, 2004
- Intel®64 and IA-32 Architectures Software Developer’s Manual, 2014. Order Number: 325462-050U
- AMD64 Architecture Programmer’s Manual Volume 1: Application Programming, 2012; Publication No. 24592, Revision 3.19
- GCC, The GNU Compiler Collection. Available online: http://gcc.gnu.org/ (accessed on 24 July 2014).
- The LLVM Compiler Infrastructure. Available online: http://llvm.org/ (accessed on 24 July 2014).
- Free Pascal. Available online: http://www.freepascal.org/ (accessed on 24 July 2014).
- Preud’homme, T.; Maintainer. The Tiny C Compiler. Available online: http://bellard.org/tcc/ (accessed on 24 July 2014).
- Portable C Compiler. Available online: http://pcc.ludd.ltu.se/ (accessed on 24 July 2014).
- STANDARD ECMA-55 Minimal BASIC. Eurpean Computer Manufacturers Association: Geneva, Switzerland, 1978.
- Anvin, H.P.; (Maintainer). Netwide Assembler. Available online: http://nasm.us/ (accessed on 24 July 2014).
- Clifton, N.; (Head Maintainer). GNU Binutils. Available online: http://www.gnu.org/software/binutils/ (accessed on 24 July 2014).
- Matz, M.; Hubička, J.; Jaeger, A.; Mitchell, M. System V Application Binary Interface AMD64 Architecture Processor Supplement Draft Version 0.99.6; 2013. [Google Scholar]
- Turbo Debugger® Version 2.0 User’s Guide, 1990
- Alves, P.; Brobecker, J.; Evans, D.; Kratochvil, J.; Tromey, T.; Zaretskii, E.; (Maintainers). GDB: The GNU Project Debugger. Available online: http://www.gnu.org/software/gdb/ (accessed on 24 July 2014).
- Saha, S.; (Maintainer). Data Display Debugger. Available online: http://www.gnu.org/software/ddd/ (accessed on 24 July 2014).
- DWARF Debugging Standard. Available online: http://www.dwarfstd.org/ (accessed on 24 July 2014).
- Teran, E. edb debugger. Available online: https://code.google.com/p/edb-debugger/ (accessed on 24 July 2014).
- Hauser, J.R. Handling Floating-point Exceptions in Numeric Programs. ACM Trans. Program. Lang. Syst. 1996, 18, 139–174. [Google Scholar] [CrossRef]
- Seyfarth, R. Introduction to 64 Bit Intel Assembly Language Programming for Linux, 2nd ed.; CreateSpace Independent Publishing Platform: North Charleston, SC, USA, 2012. [Google Scholar]
- IEEE Standard for Floating-Point Arithmetic. In Technical Report, Microprocessor Standards Committee of the IEEE Computer Society; IEEE Computer Society: New York, NY, USA, 1985.
- List of Intel Core 2 microprocessors. Available online: http://en.wikipedia.org/wiki/List_of_Intel_Core_2_microprocessors (accessed on 24 July 2014).
- Intel® SSE4 Programming Reference, 2007. Reference Number: D91561-001
- Denman, H.H. Minimax Polynomial Approximation. Math. Comput. 1966, 20, 257–265. [Google Scholar] [CrossRef]
- Hart, J.F.; Cheney, E.W.; Lawson, C.L.; Maehly, H.J.; Mesztenyi, C.K.; Rice, J.R.; Thacher, H.G., Jr.; Witzgall, C. Computer Approximations; SIAM Series in Applied Mathematics, R. E., Ed.; Krieger Pub. Co.: Malabar, FL, USA, 1978. [Google Scholar]
- Green, R. Faster Math Functions. In Proceedings of Game Developers Conference; UBM Tech: New York, NY, USA, 2003. [Google Scholar]
- Goldberg, D. What Every Computer Scientist Should Know About Floating-point Arithmetic. ACM Comput. Surv. 1991, 23, 5–48. [Google Scholar] [CrossRef]
- Brent, R.P. Fast algorithms for high-precision computation of elementary functions. In Proceedings of 7th Conference on Real Numbers and Computers (RNC 7), Nancy, France, 10–12 July 2006; pp. 7–8.
- Freely Distributable LIBM C math library verison 5.3. Available online: http://www.validlab.com/software/ (accessed on 24 July 2014).
- Shibata, N. Efficient evaluation methods of elementary functions suitable for SIMD computation. Comput. Sci.-Res. Dev. 2010, 25, 25–32. [Google Scholar] [CrossRef]
- Shibata, N. SLEEF version 2.80. Available online: http://shibatch.sourceforge.net/ (accessed on 24 July 2014).
- Robert, J.; Jenkins, J. ISAAC. In Proceedings of the Third International Workshop on Fast Software Encryption; Springer-Verlag: London, UK, 1996; pp. 41–49. [Google Scholar]
- Robert, J.; Jenkins, J. ISAAC: A fast cryptographic random number generator. Available online: http://burtleburtle.net/bob/rand/isaacafa.html (accessed on 24 July 2014).
- Arnold, R.S.; Brown, M.; Eggert, P.; Jelinek, J.; Kuvyrkov, M.; McGrath, R.; Myers, J.; O’Donell, C.; Oliva, A.; Schwab, A.; (Maintainers). The GNU C Library. Available online: http://www.gnu.org/software/libc/ (accessed on 24 July 2014).
- Clinger, W.D. How to Read Floating Point Numbers Accurately. SIGPLAN Not. 1990, 25, 92–101. [Google Scholar] [CrossRef]
- Guy, L.; Steele, J.; White, J.L. How to Print Floating-point Numbers Accurately. In Proceedings of the ACM SIGPLAN 1990 Conference on Programming Language Design and Implementation; Association of Computer Machinery: New York, NY, USA, 1990; pp. 112–126. [Google Scholar]
- Burger, R.G.; Dybvig, K.R. Printing Floating-point Numbers Quickly and Accurately. In Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation; Association of Computer Machinery: New York, NY, USA, 1996; pp. 108–116. [Google Scholar]
- Gay, D.M. Correctly rounded binary-decimal and decimal-binary conversions. Numerical Analysis Manuscript 90–10 1990. [Google Scholar]
- Gay, D.M. dtoa.c & g_fmt.c. Available online: http://netlib.org/fp/ (accessed on 24 July 2014).
- Cowlishaw, M.F. The Design of the REXX Language. SIGPLAN Not. 1987, 22, 26–35. [Google Scholar] [CrossRef]
- Henry, S.; Warren, J. Hacker’s Delight, Second Edition; Addison-Wesley/Pearson Education, Inc.: Courier in Westford, MA, USA, 2013. [Google Scholar]
- McKeeman, W.M. Peephole Optimization. Commun. ACM 1965, 8, 443–444. [Google Scholar] [CrossRef]
- Valgrind’s Memcheck. Available online: http://www.valgrind.org/ (accessed on 24 July 2014).
- Serebryany, K.; Bruening, D.; Potapenko, A.; Vyukov, D. AddressSanitizer: A Fast Address Sanity Checker. In Proceedings of the 2012 USENIX Conference on Annual Technical Conference (USENIX ATC’12); USENIX Association: Berkeley, CA, USA, 2012. [Google Scholar]
- ISO/IEC G14/N1124 Comittee Draft of ISO/IEC 9899:TC2, 2005
- Intel® Xeon Phi™ Coprocessor Instruction Set Architecture Reference Manual, 2012. Reference Number: 327364-001
- Fraser, C.W.; Hanson, D.R. A Retargetable C Compiler: Design and Implementation; Addison-Wesley Longman Publishing Co., Inc.: Boston, MA, USA, 1995. [Google Scholar]
- Aho, A.V.; Sethi, R.; Ullman, J.D. Compilers Principles, Techniques, and Tools; Addison-Wesley Longman Publishing Co., Inc.: Boston, MA, USA, 1986. [Google Scholar]
- Guntheroth, K. The New ANSI BASIC Standard. SIGPLAN Not. 1983, 18, 50–59. [Google Scholar] [CrossRef]
- STANDARD ECMA-116 BASIC.; Eurpean Computer Manufacturers Association: Geneva, Switzerland, 1986.
- Intel® 64 and IA-32 Architectures Optimization Reference Manual, 2014. Order Number: 248966-029
- Intel® Avanced Vector Extensions Programming Reference, 2011. Reference Number: 319433-011
- Firasta, N.; Buxton, M.; Jinbo, P.; Nasri, K.; Kuo, S. Intel® AVX: New Frontiers in Performance Improvements and Energy Efficiency. 2008. (White Paper). [Google Scholar]
- Felker, R.; (Maintainer). The musl C standard library. Available online: http://www.musl-libc.org/ (accessed on 24 July 2014).
- Curnow, H.J.; Wichmann, B.A. A synthetic benchmark. Comput. J. 1976, 19, 43–49. [Google Scholar] [CrossRef]
- GNU General Public License. 1991. Available online: http://www.gnu.org/licenses/gpl-2.0.html (accessed on 24 July 2014).
- 1.gcc version 4.9.1 has more than 4 million lines of source code, clang/LLVM version 3.4.2 has more than 2 million lines of source code.
- 2.Initial SSE4 support has now been implemented. See “New Developments” on page 101 for details.
- 3.See “GOSUB and RETURN Statements” on page 85.
- 4.Compiling with bounds checking support with those compilers requires using the address sanitizer system.
- 5.See “Peephole Optimizer” on page 99
- 6.NBS Test programs 26 & 38.
- 7.NBS Test program 100.
- 8.NBS Test program 129.
- 9.NBS Test programs 134 & 136.
© 2014 by the authors; licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution license (http://creativecommons.org/licenses/by/3.0/).
Share and Cite
Ham, J.G. An ECMA-55 Minimal BASIC Compiler for x86-64 Linux®. Computers 2014, 3, 69-116. https://doi.org/10.3390/computers3030069
Ham JG. An ECMA-55 Minimal BASIC Compiler for x86-64 Linux®. Computers. 2014; 3(3):69-116. https://doi.org/10.3390/computers3030069
Chicago/Turabian StyleHam, John Gatewood. 2014. "An ECMA-55 Minimal BASIC Compiler for x86-64 Linux®" Computers 3, no. 3: 69-116. https://doi.org/10.3390/computers3030069
APA StyleHam, J. G. (2014). An ECMA-55 Minimal BASIC Compiler for x86-64 Linux®. Computers, 3(3), 69-116. https://doi.org/10.3390/computers3030069