Code archives/Miscellaneous/Basic BASIC interpreter
This code has been declared by its author to be Public Domain code.
Download source code
| I done this cos I was interested in how BP works... and this is enough! :) |
;Basic BASIC Interpreter ;Version 0.7 ;Written by Michael Denathorn 2005 (www.dabzware.co.uk) ; ;Not the neatest of code, but not bad for a plasterer!!! ;See the Test.txt file for source code example (Which will run :) ) ; ;Note: If anyone finds this useful, all I ask is a mention somewhere ; in your credits... Thanks!!! ;) ;Note 2: At the moment, you cannot assign two strings together e.g. ; ; a$ = "One string" + " Two string" ; ; I did have a little bother with it (it seemed to miss the '+' operator ; To fix it, find the left string operand token first (Just like in the INTEGER & FLOAT_ ; IF statements). Then use the following before calling Get_Token() to check if it's a ; DELIMITER token (Or a operator to you or me!!!):- ; ; currentToken = currentToken + 1 ; ; This should pick up the '+' operator when you call Get_Token(), then you can ; safely move on to checking the right String operand!!! That should work!!!:) Const INVALID_FILE = 0 Const UNEXPECT_END_OF_LINE = 1 Const UNDEFINED_VARIABLE = 2 Const TO_MANY_LINES_IN_CODE = 3 Const SYNTAX_ERROR = 4 Const VARIABLE_NOT_DEFINED = 5 Const UNEXPECTED_EOF = 6 Const LINES = 100, TOKENS = 255 Const USER_VARIABLE_AMOUNT = 100 Const USER_VARIABLE_TYPES = 2 Const COMMANDS_AMOUNT = 6 Dim command$(COMMANDS_AMOUNT) command$(0) = "integer" :Const INTEGER = 0 command$(1) = "print" :Const PRINT_ = 1 command$(2) = "input" :Const INPUT_ = 2 command$(3) = "string" :Const CHARSTRING = 3 command$(4) = "float" :Const FLOAT_ = 4 command$(5) = "end" :Const END_ = 5 command$(6) = "write" :Const WRITE_ = 6 Const operators$ = "+-*^/%=()><" Const alpha$ = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ" Const DELIMITER = 1 Const VARIABLE = 2 Const NUMBER = 3 Const ACOMMAND = 4 Const STRING_ = 5 Const QUOTE = 6 Const ADD = 1 Const SUBTRACT = 2 Const MULTIPLY = 3 Const DIVIDE = 4 ;Token stuff Dim tokenBank$(LINES,TOKENS) Global tok$ Global currentLine,currentToken ;arrays to hold user defined variables Dim userVarName$(USER_VARIABLE_AMOUNT) Dim userVarType(USER_VARIABLE_AMOUNT) Dim userVarInt(USER_VARIABLE_AMOUNT) Dim userVarFloat#(USER_VARIABLE_AMOUNT) Dim userVarString$(USER_VARIABLE_AMOUNT) Global variableCount,currentVarPointer ;Load source code Load_Source() main() ;Main Function Function main() currentToken = -1 currentLine = 0 Repeat token_type = Get_Token() If token_type = VARIABLE token_type = Assignment() End If If token_type = ACOMMAND Select tok$ Case INTEGER SetVar(INTEGER) Case PRINT_ DoOutput(PRINT_) Case INPUT_ DoInput() Case CHARSTRING SetVar(CHARSTRING) Case FLOAT_ SetVar(FLOAT_) Case END_ Notify "Program Finished" End Case WRITE_ DoOutput(WRITE_) End Select End If Forever End Function ;Input function Function DoInput() inputPrompt$ = ">" return_type = get_token() If return_type = QUOTE tok$ = Left(tok$,Len(tok$)-1) tok$ = Right$(tok$,Len(tok$)-1) inputPrompt$ = tok$ currentToken = currentToken + 1 get_Token() End If If DoesVariableExist() = False Then error(VARIABLE_NOT_DEFINED,("Variable [ "+tok$+" ]")) assignmentVar = currentVarPointer tempInput$ = Input$(inputPrompt$) If userVarType(assignmentVar) = INTEGER Then userVarInt(assignmentVar) = Int(tempInput$):Return If userVarType(assignmentVar) = FLOAT_ Then userVarFloat(assignmentVar) = Float(tempInput$):Return If userVarType(assignmentVar) = CHARSTRING Then userVarString$(assignmentVar) = tempInput$:Return error(SYNTAX_ERROR,"Illegal function parameter") End Function ;Print & Write function Function DoOutput(output_type) return_type = Get_Token() If return_type = NUMBER If output_type = PRINT_ Then Print Int(tok$) If output_type = WRITE_ Then Write Int(tok$) Return End If If return_type = VARIABLE If DoesVariableExist() = False Then error(VARIABLE_NOT_DEFINED,("Variable [ "+tok$+" ]")) If userVarType(currentVarPointer) = INTEGER If output_type = PRINT_ Then Print Int(userVarInt(currentVarPointer)) If output_type = WRITE_ Then Write Int(userVarInt(currentVarPointer)) Return End If If userVarType(currentVarPointer) = FLOAT_ If output_type = PRINT_ Then Print Float(userVarFloat(currentVarPointer)) If output_type = WRITE_ Then Write Float(userVarFloat(currentVarPointer)) Return End If If userVarType(currentVarPointer) = CHARSTRING If output_type = PRINT_ Then Print userVarString$(userVarPointer) If output_type = WRITE_ Then Write userVarString$(userVarPointer) Return End If End If If return_type = QUOTE tok$ = Left(tok$,Len(tok$)-1) tok$ = Right$(tok$,Len(tok$)-1) If output_type = PRINT_ Then Print tok$ If output_type = WRITE_ Then Write tok$ Return End If error(SYNTAX_ERROR,"Illegal function parameter") End Function ;Massive function. which can easily be re-coded, but at this present time, I cannot be arsed!!! Function Assignment() If DoesVariableExist() = False error(VARIABLE_NOT_DEFINED,("Variable [ "+tok$+" ]")) End If assignmentVar = currentVarPointer If userVarType(assignmentVar) = INTEGER Local lIntOperand% Local rIntOperand% return_type = Get_Token() If return_type = DELIMITER If tok$ = "=" ; Else error(SYNTAX_ERROR,"Invalid assignment operator") End If Else error(SYNTAX_ERROR,"Missing operator") End If return_type = Get_Token() Select(return_type) Case NUMBER lIntOperand = Int(tok$) Case VARIABLE If DoesVariableExist() = False Then error(VARIABLE_NOT_DEFINED,("Variable [ "+tok$+" ]")) lIntOperand = userVarInt(currentVarPointer) Default error(SYNTAX_ERROR,"Invalid assignment,see left operand") End Select return_type = Get_Token() If return_type <> DELIMITER userVarInt(assignmentVar) = lIntOperand Return return_type End If If tok$ = "+" Then mathsOperation = ADD If tok$ = "-" Then mathsOperation = SUBTRACT If tok$ = "*" Then mathsOperation = MULTIPLY If tok$ = "/" Then mathsOperation = DIVIDE return_type = Get_Token() Select(return_type) Case NUMBER rIntOperand = Int(tok$) Case VARIABLE If DoesVariableExist() = False Then error(VARIABLE_NOT_DEFINED,("Variable [ "+tok$+" ]")) rIntOperand = userVarInt(currentVarPointer) Default error(SYNTAX_ERROR,"Invalid assignment,see right operand") End Select Select mathsOperation Case ADD userVarInt(assignmentVar) = lIntOperand + rIntOperand Case SUBTRACT userVarInt(assignmentVar) = lIntOperand - rIntOperand Case MULTIPLY userVarInt(assignmentVar) = lIntOperand * rIntOperand Case DIVIDE userVarInt(assignmentVar) = lIntOperand + rIntOperand Default error(SYNTAX_ERROR,"Unknown mathmatical operator") End Select Return End If If userVarType(assignmentVar) = FLOAT_ Local lFloatOperand# Local rFloatOperand# return_type = Get_Token() If return_type = DELIMITER If tok$ = "=" ; Else error(SYNTAX_ERROR,"Invalid assignment operator") End If Else error(SYNTAX_ERROR,"Missing operator") End If return_type = Get_Token() Select(return_type) Case NUMBER lFloatOperand = Int(tok$) Case VARIABLE If DoesVariableExist() = False Then error(VARIABLE_NOT_DEFINED,("Variable [ "+tok$+" ]")) lFloatOperand = userVarFloat(currentVarPointer) Default error(SYNTAX_ERROR,"Invalid assignment,see left operand") End Select return_type = Get_Token() If return_type <> DELIMITER userVarFloat(assignmentVar) = lFloatOperand Return return_type End If If tok$ = "+" Then mathsOperation = ADD If tok$ = "-" Then mathsOperation = SUBTRACT If tok$ = "*" Then mathsOperation = MULTIPLY If tok$ = "/" Then mathsOperation = DIVIDE return_type = Get_Token() Select(return_type) Case NUMBER rFloatOperand = Float(tok$) Case VARIABLE If DoesVariableExist() = False Then error(VARIABLE_NOT_DEFINED,("Variable [ "+tok$+" ]")) rFloatOperand = userVarFloat(currentVarPointer) Default error(SYNTAX_ERROR,"Invalid assignment,see right operand") End Select Select mathsOperation Case ADD userVarFloat#(assignmentVar) = lFloatOperand + rFloatOperand Case SUBTRACT userVarFloat#(assignmentVar) = lFloatOperand - rFloatOperand Case MULTIPLY userVarFloat#(assignmentVar) = lFloatOperand * rFloatOperand Case DIVIDE userVarFloat#(assignmentVar) = lFloatOperand + rFloatOperand Default error(SYNTAX_ERROR,"Unknown mathmatical operator") End Select Return End If error(SYNTAX_ERROR,"?????") End Function ;Check if a variable name is already stored Function DoesVariableExist() currentVarPointer = -1 For loopUserVars = 0 To variableCount If tok$ = userVarName$(loopUserVars) currentVarPointer = loopUserVars Return True End If Next Return False End Function ;Store the variable Function SetVar(dataType) return_type = Get_Token() If return_type = VARIABLE If dataType = INTEGER userVarName$(variableCount) = tok$ return_type = Get_Token() userVarType(variableCount) = INTEGER If return_type = DELIMITER If tok$ = "=" Get_Token() userVarInt(variableCount) = Int(tok$) Else error(SYNTAX_ERROR,"Invalid assignment operator") End If variableCount = variableCount + 1 End If End If If dataType = FLOAT_ userVarName$(variableCount) = tok$ return_type = Get_Token() userVarType(variableCount) = FLOAT_ If return_type = DELIMITER If tok$ = "=" Get_Token() userVarFloat(variableCount) = Float(tok$) Else error(SYNTAX_ERROR,"Invalid assignment operator") End If variableCount = variableCount + 1 End If End If If dataType = CHARSTRING userVarName$(variableCount) = tok$ return_type = Get_Token() userVarType(variableCount) = CHARSTRING If return_type = DELIMITER If tok$ = "=" Get_Token() tok$ = Left(tok$,Len(tok$)-1) tok$ = Right$(tok$,Len(tok$)-1) userVarString$(variableCount) = tok$ Else error(SYNTAX_ERROR,"Invalid assignment operator") End If variableCount = variableCount + 1 End If End If Else error(SYNTAX_ERROR,"???") End If End Function ;Work out what the next token is Function Get_Token() tok$ = "" token_word = False ;Move up a token currentToken = currentToken + 1 ;Check if token exists, if not,reset line If tokenBank$(currentLine,currentToken) = "" currentLine = currentLine + 1 If currentLine = LINES Then error(TO_MANY_LINES_IN_CODE,currentLine) currentToken = 0 If tokenBank$(currentLine,currentToken) = "" Then error(UNEXPECTED_EOF,"") End If ;Check if token is an operator For checkOperator = 1 To Len(operators$) If Mid$(operators$,checkOperator,1) = tokenBank$(currentLine,currentToken) tok$ = tokenBank$(currentLine,currentToken) Return DELIMITER End If Next ;Check if token is a string If Left$(tokenBank$(currentLine,currentToken),1) = Chr$(34) tok$ = tokenBank$(currentLine,currentToken) Return QUOTE End If ;Check if token is a number For checkDigit = 0 To 9 If Left$(tokenBank$(currentLine,currentToken),1) = Str(checkDigit) tok$ = tokenBank$(currentLine,currentToken) Return NUMBER End If Next ;Check if token is a word For searchAlpha = 1 To Len(alpha$) If Mid$(alpha$,searchAlpha,1) = Left$(tokenBank$(currentLine,currentToken),1) token_word = STRING_ End If Next ;Check if word is a command or a variable If token_word = STRING_ For checkCommand = 0 To COMMANDS_AMOUNT If tokenBank$(currentLine,currentToken) = command$(checkCommand) tok$ = Str(checkCommand) Return ACOMMAND End If Next tok$ = tokenBank$(currentLine,currentToken) Return VARIABLE End If error(SYNTAX_ERROR,"t"+tok$) End End Function ;Load Source code function ;Probably a bit of over-kill too LOL Function Load_Source() Local inString = 1 filename$ = RequestFile$("","",False) filein = ReadFile(filename$) If filein = 0 Then error(INVALID_FILE,filename$) Repeat .Skip tempLine$ = Lower$(ReadLine$(filein)) Select(tempLine$) Case "" ;BlankLine Default If Right$(templine$,1) <> ";" Then error(UNEXPECT_END_OF_LINE,tempLine$) ;If Left$(templine$,2) = "//" Then Goto Skip .SearchAgain For searchString = 1 To Len(tempLine$) If Mid$(tempLine$,searchString,1) = Chr$(34) tempString$ = Chr$(34) For getString = (searchString+1) To Len(tempLine$) tempChar$ = Mid$(tempLine$,getString,1) If tempChar$ = Chr$(34) Then Exit tempString$ = tempString$ + tempChar$ Next tempString$ = tempString$ + Chr$(34) tokenBank$(currentLine,currentToken) = tempString$ currentToken = currentToken + 1 tempLine$ = Right$(templine$,(Len(templine$)-getString)) Goto SearchAgain End If If Mid$(tempLine$,searchString,1) = Chr$(32) Or Mid$(tempLine$,searchString,1) = ";" tokenBank$(currentLine,currentToken) = Left$(tempLine$,searchString-1) currentToken = currentToken + 1 tempLine$ = Right$(templine$,(Len(templine)-searchString)) Goto SearchAgain End If Next currentToken = 0 currentLine = currentLine + 1 End Select Until Eof(filein) CloseFile filein End Function ;If there's an error, notify the user Function error(err,detail$) Select err Case INVALID_FILE Notify "Invalid source file."+Chr$(13)+Chr$(13)+"DETAIL:-"+Chr$(13)+"Cannot open file "+Chr$(13)+detail$ End Case UNEXPECT_END_OF_LINE Notify "Unexpected end of line."+Chr$(13)+Chr$(13)+"Error occured on code line "+(currentLine+1)+Chr$(13)+"DETAIL:-"+Chr$(13)+detail$ End Case TO_MANY_LINES_IN_CODE Notify "Source file to large."+Chr$(13)+Chr$(13)+"DETAIL:-"+Chr$(13)+"Maximum amount of lines breached" End Case SYNTAX_ERROR Notify "Syntax error."+Chr$(13)+Chr$(13)+"Error occured on code line "+(currentLine+1)+Chr$(13)+"DETAIL:-"+Chr$(13)+detail$ End Case VARIABLE_NOT_DEFINED Notify "Variable not defined."+Chr$(13)+Chr$(13)+"Error occured on code line "+(currentline+1)+Chr$(13)+"DETAIL:-"+Chr$(13)+detail$ End Case UNEXPECTED_EOF Notify "Expected end of file" End End Select End Function ;Basic BASIC Interpreter Source code ;Store the below in a text file or something! ; ;string name = ""; ;integer age = 0; ;integer auldAge = 0; ;input "What is your name:" name; ;input "What is your age:" age; ;print ""; ;write "You are "; ;write name; ;write " and you are "; ;write age; ;print " years old"; ;auldAge = age + 10; ;write "In a decade, you'll be "; ;write auldAge; ;write " years old"; ;print ""; ;print "You auld sod!!!"; ;end; |