{"id":32955324,"url":"https://github.com/mayuropensource/PuffinBASIC","last_synced_at":"2025-11-17T16:02:14.332Z","repository":{"id":72404190,"uuid":"287962309","full_name":"mayuropensource/PuffinBASIC","owner":"mayuropensource","description":"BASIC interpreter written in Java","archived":false,"fork":false,"pushed_at":"2020-10-13T20:03:36.000Z","size":10727,"stargazers_count":32,"open_issues_count":0,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-07-02T01:51:56.491Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mayuropensource.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-08-16T14:42:38.000Z","updated_at":"2024-05-08T13:02:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"416d2c22-cbcb-4656-86bd-c2ff81c004f7","html_url":"https://github.com/mayuropensource/PuffinBASIC","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mayuropensource/PuffinBASIC","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mayuropensource%2FPuffinBASIC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mayuropensource%2FPuffinBASIC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mayuropensource%2FPuffinBASIC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mayuropensource%2FPuffinBASIC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mayuropensource","download_url":"https://codeload.github.com/mayuropensource/PuffinBASIC/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mayuropensource%2FPuffinBASIC/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284911789,"owners_count":27083425,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-17T02:00:06.431Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-11-12T22:00:43.627Z","updated_at":"2025-11-17T16:02:14.325Z","avatar_url":"https://github.com/mayuropensource.png","language":"Java","readme":"\u003cimg src=\"puffin.png\" width=\"64\"/\u003e\n\n# PuffinBASIC\nA cross-platform modern BASIC compiler/interpreter written in Java.\n\nBASIC (Beginners' All-purpose Symbolic Instruction Code) is a general-purpose high-level\nlanguage from the 1960s. PuffinBASIC is an implementation of the BASIC language specification.\nPuffinBASIC conforms most closely to GWBASIC.\n\n## Show Case\n\n### 2D Scrolling Game (Teaser)\n\nYouTube Video: \u003ca href=\"https://youtu.be/m3snkPVhhVo\"\u003e\u003cimg src=\"samples/nextGame.png\"\u003e\u003c/a\u003e\nSource: Under development, not committed yet\n\n### TESSEL - A 2D Tile Game\nYouTube Video: \u003ca href=\"https://youtu.be/L8xkM-g3Zms\"\u003e\u003cimg src=\"samples/tessel/images/tesselsnap1.png\" width=\"64\"\u003e\u003c/a\u003e\nSource: \u003ca href=\"samples/tessel/tessel.bas\"\u003etessel.bas\u003c/a\u003e\n\n### FlyPuffinFly - A Scrolling Game\nYouTube Video: \u003ca href=\"https://youtu.be/bIIamQp9N3o\"\u003e\u003cimg src=\"samples/puffingame/images/flypuffinflysnap.png\" width=\"64\"\u003e\u003c/a\u003e\nSource: \u003ca href=\"samples/puffingame/flypuffinfly.bas\"\u003eflypuffinfly.bas\u003c/a\u003e\n\n### Conway's Game of Life\nYouTube Video: \u003ca href=\"https://youtu.be/TpsxQrxKqdg\"\u003e\u003cimg src=\"samples/gameoflife/images/gameoflifesnap.png\" width=\"64\"\u003e\u003c/a\u003e\n\u003ca href=\"https://youtu.be/A5tN6cBqoAc\"\u003e#2\u003c/a\u003e\nSource: \u003ca href=\"samples/gameoflife/gameoflife.bas\"\u003egameoflife.bas\u003c/a\u003e\n\n### Mandelbrot Set\nYouTube Video: \u003ca href=\"https://youtu.be/7CukYv9tfXA\"\u003e\u003cimg src=\"samples/mandelbrotsnap.png\" width=\"64\"\u003e\u003c/a\u003e\n\u003ca href=\"https://youtu.be/xKp9U2BXTHM\"\u003eZoomed\u003c/a\u003e\nSource: \u003ca href=\"samples/mandelbrot.bas\"\u003emandelbrot.bas\u003c/a\u003e\n\n## Why Implement BASIC?\n\n1. Love and Familiarity: GWBASIC was my first programming language, I loved it and made many games in it.\n1. Interpreter language: BASIC is simple and an interpreted language and hence a good choice for implementing this interpreter.\n1. Learn antlr4: I was learning antlr4 and BASIC was the perfect language to try because \nof its simple instruction set.\n1. Resurrect BASIC: Implementations such as GWBASIC don't work on most modern platforms. \nMy goal is to make PuffinBASIC work anywhere Java can work.\n1. Improve BASIC: I wanted to add modern graphics, better data types, etc., to make it easier to write games.\n\n## Version\n\n0.1 experimental (NOT YET READY FOR PRODUCTION USE!)\n\n- The interpreter is not yet thoroughly tested and is likely to have bugs.\n- This is an active project so expect large changes at frequent intervals.\n\n## Code Samples\n\n### Print multiplication tables\n\n```\n10 FOR I% = 1 TO 10\n20   PRINT \"Multiplication table of \", I%\n30   FOR J% = 1 TO 10\n40     PRINT I%, \"x\", J%, \"=\", I%*J%\n50   NEXT J%\n60 NEXT I%\n```\n### Print prime numbers between 1 and 100\n\nLine numbers are optional in PuffinBASIC.\n\n```\nFOR I% = 1 TO 100\n  J% = 3\n  N% = I% \\ 2\n  ISPRIME% = (I% \u003e 1) AND ((I% MOD 2 \u003c\u003e 0) OR (I% = 2))\n  WHILE J% \u003c= N% AND ISPRIME% = -1\n    ISPRIME% = I% MOD J% \u003c\u003e 0\n    J% = J% + 2\n  WEND\n  IF ISPRIME% THEN PRINT STR$(I%), \" is prime\"\nNEXT I%\n```\n\n### Print Fibonacci Series\n\n```\n10 A@ = 0 : B@ = 1\n20 FOR I% = 1 TO 20\n30   C@ = A@ + B@\n40   PRINT C@,\n50   A@ = B@ : B@ = C@\n60 NEXT I%\n70 PRINT \"\"\n```\n### Print trigonometric function graph\n\n```\n10 PRINT SPACE$(40), \"0\"\n20 FOR D = 0 TO 360 STEP 10\n30   x# = 3.14159 * D / 180.0\n40   y# = SIN(x#)\n50   PRINT SPACE$(40 + CINT(y# * 40)), \"*\"\n60 NEXT D\n```\n\n### Graphics\n\n```\n10 SCREEN \"PuffinBASIC 2D Graphics\", 800, 600\n20 LINE (100, 100) - (200, 200), \"B\"\n30 FOR I% = 10 TO 50 STEP 10\n40   CIRCLE (150, 150), I%, I%\n50 NEXT I%\n60 COLOR 255, 0, 0\n70 LINE (200, 200) - (250, 300), \"BF\"\n80 COLOR 0, 255, 255\n90 FONT \"Georgia\", \"bi\", 32\n100 DRAWSTR \"Graphics with PuffinBASIC\", 10, 400\n110 DIM A%(101, 101)\n120 GET (100, 100) - (201, 201), A%\n130 PUT (250, 250), A%\n140 DIM B%(32, 32)\n150 LOADIMG \"samples/enemy1.png\", B%\n160 FOR I% = 1 TO 5\n170   PUT (400, 100 * I%), B%\n180 NEXT\n190 COLOR 255, 255, 0\n200 DRAW \"M600,400; UN50; RN50; DB50; F100\"\n210 COLOR 255, 255, 255\n220 CIRCLE (700, 100), 10, 20\n230 COLOR 255, 0, 255\n240 PAINT (700, 100), 255, 255, 255\n250 CIRCLE (700, 400), 50, 50, 0, 90\n260 CIRCLE (700, 500), 50, 50, 90, 180, \"F\"\n1000 SLEEP 5000\n```\n\n\u003cimg src=\"samples/puffin_graphics.png\" width=\"512\"/\u003e\n\n## Dependencies\nJDK 11+, Maven, antlr4\n\n## Build and test\n\n```\n$ mvn compile\n$ mvn test\n```\n\n## Run using Maven\n```\n$ mvn exec:java -D\"exec.args\"=\"samples/graph.bas\"\n```\n\nGraphics mode:\n```\n$ mvn exec:java -D\"exec.args\"=\"-g samples/graphics.bas\"\n```\n\n## Working with Intellij\n\nImport the pom.xml file in Intellij.\nAfter importing, if you make a change to the antlr4 grammar,\nregenerate the antlr4 code using following command and then reload the changes.\n```\n$ mvn generate-sources\n```\n\n## How it works?\n\n1. PuffinBASIC's grammar is defined using antlr4.\n1. The user source code is parsed using antlr4 lexer+parser.\n1. An intermediate representation (IR) is generated. \nA symbol table keeps track of variables, scalars, arrays, etc. objects.\n1. The interpreter runtime processes the IR instructions and executes them in a single thread.\nFor graphics, an optional Runtime is used.\n\nSince PuffinBASIC generates IR from source code and the runtime executes the IR, we can say PuffinBASIC is both a compiler and an interpreter.\n\n## Planned Improvements\n\n1. Android port, requires a rewrite of Graphics runtime.\n1. ...\n\n## Performance\n\nPuffinBASIC is an interpreter, and it should not be expected to have very good performance characteristics.\nCertain operations such as PRINT USING, INPUT, etc are not optimized for performance.\nPuffinBASIC primitives have not been benchmarked.\nThat being said, games containing 2D graphics work reasonably well.\n\n## Memory\n\nPuffinBASIC runs within a JVM and can use as much memory as available for the JVM process.\n\n# Reference\n\n## Mode of operation\n\n### Indirect Mode\n\n1. Write a program in your favorite editor.\n1. Save it in a text file with a '.bas' extension (not a requirement).\n1. Use maven or PuffinBasicInterpreterMain to run the program.\n\nPuffinBASIC supports indirect mode only.\n\n### Line-number and No-line-number modes\n\nPuffinBASIC programs can have one of two modes:\n1. Line-number mode: All lines must start with a line number. GOTO/GOSUB statements can use both line number and label.\n1. No-line-number mode: No line should start with a line number. GOTO/GOSUB statements can use label only.\n\n## Compatibility\n\nPuffinBASIC is mostly compatible with Microsoft's GWBASIC.\nGraphics is supported using Java 2D graphics.\n\nPuffinBASIC will not support assembly instructions.\n\n### Input\n\nPuffinBASIC aims for cross-platform compatibility and doesn't support platform specific features. \nInput statements and functions are line based and require 'ENTER' key to be pressed.\nSame applies for the sequential file writes, print statements always output a line and input statements read the whole line.\n\n### Case sensitivity\n\nOperators, Statements and Standard Functions are case-insensitive.\nConstants, variables and user defined functions are case-sensitive.\n\n### Graphics\n\nGraphics uses platform-independent Swing window.\nGraphics functions are slightly different and more general than GWBASIC.\nGraphics statements/functions require a '-g' flag to be set at runtime.\nSee Graphics section in reference.\nPRINT/WRITE statements are displayed on standard out only.\nFor displaying text on Swing window, new statements are added.\n\n### DIM\n\nDIM statement declares size of each dimension (rather than maximum value of the dimension).\n\n### Data Types\n\nPuffinBASIC supports scalar, array, struct, list, set and dict types.\nInt32, Int4, Float32, Float64, and String are the scalar types.\nEach scalar type has a corresponding array type.\n\n## Commands\n\nPuffinBASIC does not support BASIC Commands, such as LIST, RUN, etc.\n\n## Errors\n\nPuffinBASIC can raise following kind of errors:\n1. PuffinBasicSyntaxError: if source code has lexical or parsing error, e.g. missing parenthesis.\n1. PuffinBasicSemanticError: if source code has a semantic error, e.g. data type mismatch. \n1. PuffinBasicRuntimeError: if a runtime error happens, e.g. division by zero, IO error, etc.\n1. PuffinBasicInternalError: if there is a problem with PuffinBASIC implementation.\n\n## Data Types\n\n### Scalar Types\n\n1. Int32 (32-bit signed integer): Int32 constants can have an optional '%' suffix.\nInt32 constants can be decimal, octal or hexadecimal.\nOctal numbers must have '\u0026' or '\u0026O' prefix, e.g. \u002612 or \u0026O12.\nHexadecimal numbers must have '\u0026H' prefix, e.g. \u0026HFF.\n\n1. Int64 (64-bit signed integer): Int64 constants must have '@' suffix.\nInt64 constants can be decimal, octal or hexadecimal.\n\n1. Float32 (32-bit signed IEEE-754 floating-point): Float32 constants can have an optional '!' suffix.\nFloat32 constants can use a decimal format or scientific notations, e.g. 1.2 or 1.2E-2.\n\n1. Float64 (64-bit signed IEEE-754 floating-point): Float64 constants can have an optional '#' suffix.\nFloat32 constants can use a decimal format or scientific notations, e.g. 1.2 or 1.2E-2.\n\n1. String: String stores any non-newline (or carriage return) ASCII character. \nA string must be enclosed within double-quotes, e.g. \"A TEST, STRING\".\nThere is no limit on the length of a string.\n\n### Array Types\n\n1. N-dimensional Int32 Array\n1. N-dimensional Int64 Array\n1. N-dimensional Float32 Array\n1. N-dimensional Float64 Array\n1. N-dimensional String Array\n\n### Composite Types\n\n1. Struct: User defined type composed of scalar, array, struct, list, set and dict types.\n1. List: Variable length list of scalar and struct values.\n1. Set: Unordered open hash-set of scalar values.\n1. Dict: Unordered open hash-map of scalar to scalar and struct values.\n\n### Type conversion\n\nNumeric types are converted into one another via implicit type conversion.\nString and numeric types are not implicitly converted. \nUse STR$ or VAL functions for conversion between String and numeric values.\n\n## Variables\n\nA variable name must start with a letter followed by one or more letters or numeric digits.\nA variable name must not start with 'FN' because it is reserved for user defined functions.\n\nA variable name has an optional suffix which sets the data type.\nInt32 variable has '%' suffix, int64 variable has '@' suffix, float32 has '!' suffix,\nfloat64 has '#' suffix, and String has '$' suffix. \nIf a suffix is omitted, default data type assumed, the global default is Float64. \n\nThere are three kinds of variables:\n1. Scalar variable stores a single value, e.g. A%\n1. Array variable stores a multi-dimensional array. An array variable must defined using DIM statement.\nAn array can have any number of dimensions. The minimum array index is 0 and maximum is dimension length - 1.\n1. Composite variable such as struct, list, set and dict.\n\nExample:\n```\n10 DIM A%(3, 4)\n20 A%(1, 2) = 5\n```\n\n### Variable Reference\n\nA variable can reference to another variable,\nA reference variable does not have a type-suffix.\n\nSyntax:\n\n```\nAUTO refVariable = variable\n```\n\nExample:\n\n```\nA% = 10\nAUTO B = A%\nB = 3 ' Both A% and B have value 3.\n\nDIM X%(2,3)\nAUTO Y = X%\nY(0,0) = 3 ' Both X%(0,0) and Y(0,0) have value 3.\n```\n\n## Operators\n\nOrder of operations (lower number means higher precedence):\n\n1. Arithmetic\n1. Relational\n1. Logical or bit-wise\n\nFor same precedence, the order is left to right.\n\nArithmetic (lower number means higher precedence):\n1. '^'    Exponentiation\n1. '-'    Unary minus\n1. '*' or '/' or '\\\\' Multiplication or Floating point division or Integer division\n1. 'mod'  Modulus\n1. '+' or '-' Addition or Subtraction\n\nRelational operators return -1 for true and 0 for false.\nRelational operators work with both numbers and Strings.\n\nRelational (all have same precedence):\n* '='    Equals\n* '\u003c\u003e'   Not equals\n* '\u003c'    Less than\n* '\u003e'    Greate than\n* '\u003c='   Less than or equal\n* '\u003e='   Greater than or equal\n\nIf inputs to logical operators is -1 and 0, they return -1 for true and 0 for false.\nOtherwise, logical operators work like bit-wise operators.\n'\u003e\u003e' and '\u003c\u003c' are bitwise right-shift and left-shift operators.\n\nLogical or bit-wise (lower number means higher precedence):\n1. 'NOT'\n1. 'AND' or 'OR' or 'XOR' or 'EQV' or 'IMP'\n1. '\u003e\u003e' or \u003c\u003c'\n\n## Built-in functions\n\nBuilt-in functions always return a single scalar value.\nBuilt-in functions accept zero or more parameters.\n\n### Numeric Functions\n\n#### ABS\n\nReturns absolute value of a numeric expression.\n\nSyntax:\n\n```\nABS(n)\n```\n\nwhere, n is a numeric expression\n\nExample:\n\n```\nABS(-1)\n1\n```\n\n#### FIX\n\nTruncates n to a whole number.\nFor positive number, it returns the floor.\nFOr negative number, it returns the ceiling.\n\nSyntax:\n\n```\nFIX(n)\n```\n\nExample:\n\n```\nFIX(-2.3)\n-2\n```\n\n#### INT\n\nReturns the floor of the number n.\n\nSyntax:\n\n```\nINT(n)\n```\n\nExample:\n\n```\nINT(-2.3)\n-3\n```\n\n#### LOG\n\nLOG returns the natural logarithm of a numeric value.\nLOG10 returns base-10 logarithm of a numeric value.\nLOG2 returns base-2 logarithm of a numeric value.\nn must be greater than 0.\n\nSyntax:\n\n```\nLOG(n)\nLOG10(n)\nLOG2(n)\n```\n\n#### EXP\n\nReturns E raised to the power of n.\n\nSyntax:\n\n```\nEXP(n)\n```\n\n#### RND\n\nReturns the next random number between 0 and 1.\n\nSyntax:\n\n```\nRND\n```\n\n#### SQR\n\nReturns the square root of n.\nn must be greater than or equal to 0.\n\nSyntax:\n\n```\nSQR(n)\n```\n\n#### EULERE\n\nReturns the value of Euler's number E.\n\nSyntax:\n\n```\nEULERE()\n```\n\n#### PI\n\nReturns the value of PI.\n\nSyntax:\n\n```\nPI()\n```\n\n#### FLOOR, CEIL, ROUND\n\nSyntax:\n\n```\nFLOOR(n)\nCEIL(n)\nROUND(n)\n```\n\n#### MIN\n\nCalculates min of n and m.\nn and m must be numeric values.\n\nSyntax:\n\n```\nMIN(n, m)\n```\n\n#### MAX\n\nCalculates max of n and m.\nn and m must be numeric values.\n\nSyntax:\n\n```\nMAX(n, m)\n```\n\n#### Trigonometric Functions\n\nSIN, COS and TAN take angle in radians and return sine, cosine and tangent of that angle.\nTo compute angle in radians, multiply the angle in degrees with pi/180.\n\nASIN, ACOS and ATN takes a numeric value, computes arc sin, arc cos, arc tangent of the value and returns the angle in radians. \nTo compute angle is degrees, multiply the angle in radians with 180/pi.\n\nSINH, COSH and TANH are hyperbolic sin, hyperbolic cos and hyperbolic tan functions respectively.\n\nTORAD converts degrees to radians.\nTODEG converts radians to degrees.\n\nSyntax:\n\n```\nSIN(radians)\nCOS(radians)\nTAN(radians)\nASIN(value)\nACOS(value)\nATN(value)\nSINH(radians)\nCOSH(radians)\nTANH(radians)\nTORAD(degress)\nTODEG(radians)\n```\n\n### Numeric Conversion Functions\n\nThese functions are used for numeric type conversion.\nCINT(n) converts the given numeric value to int32 with bounds check.\nCLNG(n) converts the given numeric value to int64 with bounds check.\nFor CINT and CLNG, if the value is out of bounds, a DATA_OUT_OF_RANGE runtime error is thrown.\n\nCSNG(n) converts the given numeric value to float32.\nCDBL(n) converts the given numeric value to float64.\n\nSyntax:\n\n```\nCINT(n)\nCLNG(n)\nCSNG(n)\nCDBL(n)\n```\n\n### String Functions\n\n#### ASC\n\nReturns the numeric ASCII code for the first character in the string. \nIf the string is empty, an ILLEGAL_FUNCTION_PARAM runtime error is thrown.\n \nSyntax:\n\n```\nASC(x$)\n```\n\nExample:\n\n```\nASC(\"A\")\n65\n```\n\n#### CHR$\n\nConverts the given ASCII numeric value to equivalent single character string.\n\nSyntax:\n\n```\nCHR$(n)\n```\n\nExample:\n\n```\nCHR$(65)\n\"A\"\n```\n\n#### HEX$\n\nReturns the hexadecimal String equivalent of the given number.\n\nSyntax:\n\n```\nHEX$(n)\n```\n\nExample:\n\n```\nHEX$(16)\n\"10\"\n```\n\n#### OCT$\n\nReturns the octal String equivalent of the given number.\n\nSyntax:\n\n```\nOCT$(n)\n```\n\nExample:\n\n```\nOCT$(8)\n\"10\"\n```\n\n#### INSTR\n\nReturns the position (starting with 1) of the first occurrence of string y$ in string x$.\nn is the start offset of the search position, starting at 1.\nThe default value of n is 1.\nIt returns 0, if n \u003c LEN(x$), x$ is empty, or y$ is not found.\nIt returns n, if y$ is empty.\n\nSyntax:\n\n```\nINSTR([n], x$, y$)\n```\n\nExample:\n\n```\nINSTR(\"12FOO34FOO\", \"FOO\")\n3\n```\n\n#### LEFT$\n\nReturns the String with left-most n characters from string x$.\n\nSyntax:\n\n```\nLEFT$(x$, n)\n```\n\nExample:\n\n```\nLEFT$(\"ABCD\", 2)\n\"AB\"\n```\n\n#### LEN\n\nReturns the length of the String x$ in number of ASCII characters.\n\nSyntax:\n\n```\nLEN(x$)\n```\n\nExample:\n\n```\nLEN(\"ABC\")\n3\n```\n\n#### MID$\n\nReturns a String of m ASCII characters from the String x$ beginning at the nth character.\n\nIf m is omitted or is larger than remaining String length, all right-most characters beginning at n are returned.  \nIf n \u003e LEN(x$) or m is 0, empty String is returned.\n\nSyntax:\n\n```\nMID$(x$, n[, m])\n```\n\n#### RIGHT$\n\nReturns the String with right-most n characters from string x$.\n\nSyntax:\n\n```\nRIGHT(x$, n)\n```\n\nExample:\n\n```\nRIGHT(\"ABCD\", 2)\n\"CD\"\n```\n\n#### SPLIT$\n\nSplit the given string str$ using the regex and return a string array.\n\nSyntax:\n\n```\nSPLIT$(str$, regex$)\n```\n\nExample:\n\n```\nAUTO splitstrarray = SPLIT$(\"A,BB,CC\", \",\")\n```\n\n#### SPACE$\n\nReturns a String with n spaces.\n\nSyntax:\n\n```\nSPACE$(n)\n```\n\n#### STR$\n\nReturns the String representation of the value n.\n\nSyntax:\n\n```\nSTR$(n)\n```\n\n#### STRING$\n\n(First form) Returns a String of length n with all characters with the ASCII value j. \n(Second form) Returns a String of length n with all characters are the first character from x$. \nIf the string is empty, an ILLEGAL_FUNCTION_PARAM runtime error is thrown.\n\nSyntax:\n\n```\nSTRING$(n, j)\nSTRING$(n, x$)\n```\n\n#### VAL\n\nConverts a String containing a number to a numeric value.\nIt is the opposite of STR$ function.\n\nSyntax:\n\n```\nVAL(x$)\n```\n\n### Array Functions\n\n#### ARRAY1DMIN, ARRAY1DMAX, ARRAY1DMEAN, ARRAY1DSUM, ARRAY1DSTD, ARRAY1DMEDIAN, ARRAY1DPCT\n\nCompute summary and descriptive statistics on the given 1-dimensional array.\nSyntax:\n\n```\nARRAY1DMIN(arrayvariable)     ' min\nARRAY1DMAX(arrayvariable)     ' max\nARRAY1DMEAN(arrayvariable)     ' mean\nARRAY1DSUM(arrayvariable)      ' sum\nARRAY1DSTD(arrayvariable)      ' standard deviation\nARRAY1DMEDIAN(arrayvariable)   ' median\nARRAY1DPCT(arrayvariable, pct) ' percentile, where pct=0-100\n```\n\nExample:\n\n```\nARRAY1DMIN(C%)\nARRAY1DMAX(C%)\nARRAY1DMEAN(C%)\nARRAY1DSUM(C%)\nARRAY1DSTD(C%)\nARRAY1DMEDIAN(C%)\nARRAY1DPCT(C%, 90)\n```\n\n#### ARRAY1DBINSEARCH\n\nSearch the value x in the given 1-dimensional array variable.\nIf the value x is found, the index is returned.\nIf the value is not found, (-(insertion point) - 1) is returned.\n\nSyntax:\n\n```\nARRAY1DBINSEARCH(arrayvariable, x)\n```\n\nExample:\n\n```\nARRAY1DBINSEARCH(C%, 2)\n```\n\n### Packing and Unpacking Functions\n\n#### Packing\n\nThese functions are used to pack numeric values to String before being written to a\nRandom Access File.\n\nMKI$ packs Int32 to a 4 byte String.\nMKL$ packs Int64 to a 8 byte String.\nMKS$ packs Float32 to a 4 byte String.\nMKD$ packs Float64 to a 8 byte String.\n\nSyntax:\n\n```\nMKI$(n)\nMKL$(n)\nMKS$(n)\nMKD$(n)\n```\n\n#### Unpacking\n\nThese functions are used to unpack numeric values from String after being read from a\nRandom Access File.\n\nCVI unpacks Int32 from a 4 byte String. \nCVL unpacks Int64 from a 8 byte String. \nCVS unpacks Float32 from a 4 byte String. \nCVD unpacks FLoat64 from a 8 byte String. \n\nSyntax:\n\n```\nCVI(x$)\nCVL(x$)\nCVS(x$)\nCVD(x$)\n```\n\n### ENVIRON$\n\nReads the String value for the given environment variable.\n\nSyntax:\n\n```\nENVIRON$(x$)\n```\n\n### TIMER\n\nReturns number of seconds (Float64) elapsed since midnight in the local time zone.\n\nSyntax:\n\n```\nTIMER\n```\n\n### TIMERMILLIS\n\nReturns number of milliseconds (Int64) elapsed since midnight in the local time zone.\n\nSyntax:\n\n```\nTIMERMILLIS\n```\n\n### INPUT$\n\nReads n character String from the keyboard.\nThis function waits for ENTER key to be pressed and returns first n characters.\n\n```\nINPUT$(n)\n```\n\n### File handling functions\n\n#### EOF\n\nReturns -1 (true) or 0 (false) when end of file is reached\nwhile reading a sequential file.\nfilenum is the file number.\n\nSyntax:\n\n```\nEOF(filenum)\n```\n\n#### LOC\n\nReturns the current position (in record number) in the file.\nfilenum is the file number.\nFor random access file, LOC returns the record number of last PUT ot GET.\nFor sequential access file, LOC returns the number of 128-byte block read or written.\nLOC may not return exact number in case of the sequential access file.\n\nSyntax:\n\n```\nLOC(filenum)\n```\n\n#### LOF\n\nReturns the length of file in bytes.\nfilenum is the file number.\n\n```\nLOF(filenum)\n```\n\n### HSB2RGB\n\nConverts HSB color float values (each 0-1) to an int32 RGB values.\n\nSyntax:\n\n```\nHSB2RGB(hue, saturation, brightness)\n```\n\nExample:\n\n```\nHSB2RGB(0.5, 1.0, 1.0)\n```\n\n### Keyboard Functions\n\nThese functions work in graphics mode only.\n\nCheck whether the given key$ is pressed.\n\nSyntax:\n\n```\nISKEYPRESSED(key$)\n```\n\nExample:\n\n```\nisLeftArrowPressed% = ISKEYPRESSED(CHR$(0) + CHR$(37))\n```\n\n### Mouse Functions\n\nMouse functions work in graphics mode only.\n\nMouse x/y functions returns x/y coordinate relative to the window.\n\nMouse button functions return the button number. \nThey return -1 if no button was pressed since last function call.\n\nSyntax:\n\n```\nMOUSEMOVEDX()\nMOUSEMOVEDY()\nMOUSEDRAGGEDX()\nMOUSEDRAGGEDY()\nMOUSEBUTTONCLICKED()\nMOUSEBUTTONPRESSED()\nMOUSEBUTTONRELEASED()\n```\n\n## Statements\n\n### Line\n\nSource code consists of multiple lines.\n\nEach line starts with an optional integer line number.\nThe line number is followed by one or more statements and ends with an optional comment.\nMultiple statements in a line can be separated by colon (':').\n\n```\n10 LET A = 1 : PRINT A REM COMMENT\n20 REM COMMENT\n``` \n\n### Comments\n\nA comment starts with REM or single quote (\"'\").\n\nSyntax:\n```\nREM USER TEXT\n' COMMENT TEXT\n```\n\n### Libraries\n\nPuffinBASIC supports reusing source code via libraries.\n\nA library must set a unique library tag set using LIBTAG.\nLibraries cannot have line numbers.\n\nThe search path for library can be set in PUFFIN_BASIC_PATH environment variable.\nThe main source file's path is the default search path.\n\nUse IMPORT statement to import libraries.\n\nSyntax:\n\n```\nLIBFILE:\nLIBTAG \"UNIQUE LIBTAG\"\n...\n...\n\nmain.bas:\nIMPORT \"LIBFILE\"\n```\n\nExamples:\n\n```\na.bas:\nLIBTAG \"_a.bas_\"\nPRINT \"Currently in a.bas\"\n\nb.bas:\nLIBTAG \"_b.bas_\"\nIMPORT \"a.bas\"\nPRINT \"Currently in b.bas\"\n\nmain.bas:\nIMPORT \"b.bas\"\nIMPORT \"a.bas\"\nPRINT \"Currently in MAIN\"\n```\n\n### Variables\n\n#### Assignment\n\nScalar variables are declared and assigned value using LET statement.\nThe LET keyword is optional.\n\nSyntax:\n\n```\nLET variable = expr\nvariable = expr\n```\n\nExample:\n\n```\nLET A% = 1\nB$ = \"ABC\"\n```\n\n#### Reference Assignment\n\nAUTO can be used to reference the result of an expression\nwithout specifying the type of the reference variable or\nallocating the variable.\n\nSyntax:\n\n```\nAUTO refvar = expr\n```\n\nExample:\n\n```\nAUTO keys = dict1.keys()\n```\n\n#### Arrays\n\nUse DIM keyword to declare an array variable.\ndim1, dim2, ... are dimension size (and not max dim value.)\nArrays are stored in row-major order.\nThe minimum index in an array dimension is 0 and maximum is dim size - 1.\nWhen declaring variables (except within a struct and a UDF param),\nan expression can be used to set the dimension size.\n\nSyntax:\n\n```\nDIM variable(dim1, dim2, ...)\n```\n\nExample:\n\n```\nDIM A%(3, 5)\n```\n\nThe above statements declares a 3x5 Int32 variable.\n\n#### Dynamic Arrays\n\nALLOCARRAY function Dynamically allocates array.\nThe result should be assigned to a variable reference.\n\nSyntax:\n\n```\nAUTO arrayvarref = ALLOCARRAY varsuffix(dim1, dim2, ...)\n```\n\nExample: \n```\nAUTO aa1 = ALLOCARRAY%(2, 3)\n```\n\n#### Struct\n\nUser defined type composed of scalar, array, struct, list, set and dict types.\nThe array dimensions must be declared using constants in a struct.\n\nSyntax:\n\n```\nSTRUCT typename { members } ' Define the struct type.\ntypename varname {}         ' Create an instance of the type.\n```\n\nExample 1: Example of scalar types.\n\n```\nSTRUCT struct1 { A% , B% }\nstruct1 s1 {}\ns1.A% = 2\ns2.A% = 10\nPRINT s1.A%, s2.A%\n```\n\nExample 2: Nested struct.\n\n```\nSTRUCT struct2 { C%, struct1 child }\nstruct2 s3 {}\ns3.child.A% = 100\ns3.C% = 50\nPRINT s3.child.A%, s3.C%\n```\n\nExample 3: Example of all data types.\n\n```\nSTRUCT struct4 { A%, B@, C!, D#, E$, DIM ARR%(2,3), LIST\u003c$\u003e l1, SET\u003c%\u003e s1, DICT\u003c%, #\u003e d1 }\nstruct4 s41 {}\ns41.A% = 1\ns41.B@ = 2\ns41.C! = 3\ns41.D# = 4\ns41.E$ = \"str\"\ns41.ARR%(1, 1) = 5\ns41.l1.append(\"abc\")\ns41.s1.add(23)\ns41.d1.put(10, 2.5)\nPRINT s41.A%, s41.B@, s41.C!, s41.D#, s41.E$, s41.ARR%(1, 1), s41.l1.get(0), s41.s1.contains(23), s41.d1.getOrDefault(10, 0)\n```\n\n#### List\n\nA variable length list of scalar and struct values.\n\nTODO: struct value is not tested yet.\n\nSyntax:\n\n```\nLIST\u003cDATATYPE|STRUCT\u003e varname\n\nSupported functions:\nvarname.append(VALUE) ' Append the value to the list.\nvarname.get(INDEX)    ' Get the value at the given index.\nvarname.insert(INDEX, VALUE) ' Insert the value at the given index.\nvarname.values()      ' Get the array of values.\nvarname.clear()       ' Clear the list.\nLEN(varname)          ' Get the length of the list.\n```\n\nExample:\n\n```\nLIST\u003c$\u003e list1\nlist1.append(\"a\")\nlist1.append(\"b\")\nPRINT list1.get(0)\n\nauto l1val = list1.values()\nFOR I% = 0 TO LEN(l1val) - 1\n  PRINT l1val(I%),\nNEXT : PRINT \"\"\n\nlist1.insert(0, \"c\")\nlist1.clear()\n```\n\n#### Set\n\nAn unordered open hash-set of scalar values.\n\nSyntax:\n\n```\nSET\u003cDATATYPE\u003e varname\n\nSupported functions:\nvarname.add(VALUE)      ' Add the VALUE to the set.\nvarname.contains(VALUE) ' Check if the VALUE exists in the set.\nvarname.values()        ' Get the array of unordered values.\nvarname.remove(VALUE)   ' Remove the VALUE from the set if it exists.\nvarname.clear()         ' Clear the set.\nLEN(varname)            ' Get the length of the set.\n```\n\nExample:\n\n```\nSET\u003c$\u003e set1\n\nset1.add(\"a\")\nPRINT set1.contains(\"a\")\n\nauto s1val = set1.values()\nFOR I% = 0 TO LEN(s1val) - 1\n  PRINT s1val(I%),\nNEXT : PRINT \"\"\n\nset1.remove(\"a\")\nset1.clear()\nPRINT LEN(set1)\n```\n\n#### Dict\n\nAn unordered open hash-map of scalar key to scalar/struct values.\n\nTODO: struct values are not tested yet.\n\nSyntax:\n\n```\nDICT\u003cKEYTYPE, VALUETYPE|STRUCT\u003e varname\n\nSupported functions:\nvarname.put(KEY, VALUE)  ' Put the KEY/VALUE pair in the dict, overwriting any previous value.\nvarname.getOrDefault(KEY, DEFAULT_VALUE)  ' Get the value of the KEY if present, DEFAULT_VALUE if absent.\nvarname.removeKey(KEY)   ' Remove the KEY from the dict if it exists.\nvarname.containsKey(KEY) ' Check if the KEY exists in the dict.\nvarname.keys()           ' Get the array of keys in the dict.\nvarname.clear()          ' Clear the dict.\nLEN(varname)             ' Get the length of the dict.\n```\n\nExample:\n\n```\nDICT\u003c$,%\u003e dict1\n\ndict1.put(\"a\", 65)\n\nauto d1val = dict1.keys()\nFOR I% = 0 TO LEN(d1val) - 1\n  PRINT d1val(I%),\nNEXT : PRINT \"\"\n\nPRINT dict1.removeKey(\"a\")\nPRINT dict1.getOrDefault(\"a\", -1)\nPRINT dict1.containsKey(\"a\")\n\ndict1.clear()\nPRINT LEN(dict1)\n```\n\n### Default Variable Data Type\n\nThe following keywords can be used to declare default data type of a variable,\n(used when a variable does not have a suffix).\n\nSyntax:\n\n```\nDEFINT letter-letter[, letter-letter]\nDEFLNG letter-letter[, letter-letter]\nDEFSNG letter-letter[, letter-letter]\nDEFDBL letter-letter[, letter-letter]\n```\n\nExample:\n\n```\nDEFINT A-C\n```\n\nThe above example declares variables starting with A, B and C as Int32.\n\n### Control Statements\n\n#### IF-THEN-ELSE\n\nIn case of nested IF-THEN-ELSE, ELSE matches the closest IF statement.\n\nSyntax:\n\n```\nIF expression THEN statements ELSE statements\n```\n\nExample:\n\n```\nIF A \u003e 1 THEN PRINT \"A \u003e 1\" ELSE PRINT \"A \u003c= 1\"\n```\n\n#### IF-GOTO-ELSE\n\nSyntax:\n\n```\nIF expression GOTO linenumber ELSE statements\n```\n\nExample:\n\n```\n20 IF A \u003e 1 GOTO 100 ELSE 200\n```\n\n#### IF-THEN-BEGIN-ELSE-BEGIN-END_IF\n\nPuffinBASIC supports then/else blocks with IF statement.\n\nSyntax:\n\n```\nIF expr THEN BEGIN\n  stmt1\n  stmt2\n  ...\nELSE BEGIN\n  stmtk\n  stmtk+1\n  ...\nEND IF\n```\n\nExample:\n\n```\nIF A% \u003c 20 THEN BEGIN\n  PRINT A%, \"LT 20\"\nELSE BEGIN\n  PRINT A%, \"GE 20\"\nEND IF\n```\n\n#### LABEL\n\nCreate a label.\nGOSUB/GOTO can be used with the label name.\n\nSyntax:\n\n```\nLABEL \"labelname\"\n```\n\nExample:\n\n```\nLABEL \"DRAW A LINE\"\n```\n\n#### GOTO\n\nJump to the given line number.\nIn no-linenumber mode, GOTO can be used with label.\n\nSyntax:\n\n```\n20 GOTO 100\n\nGOTO \"label\"\n```\n\n#### FOR-NEXT-STEP\n\nFor loop.\n\nSyntax:\n\n```\nFOR variable = expression TO expression [STEP expression]\n...\nNEXT [variable]\n```\n\nExample:\n\n```\n10 FOR I% = 1 TO 10 STEP 2\n20 PRINT I%\n30 NEXT I%\n```\n\n#### WHILE-WEND\n\nWhile loop.\n\nSyntax:\n\n```\nWHILE expression\n...\nWEND\n```\n\nExample:\n\n```\n20 WHILE A \u003c 10\n30 A = A + 1\n40 PRINT A\n50 WEND\n```\n\n#### END\n\nMarks the end of the program.\n\n#### GOSUB-RETURN\n\nGoto the subroutine. After subroutine finishes (on RETURN statement), \nthe program execution returns to the statement after GOSUB.\nSubroutines should be defined at the end of the program.\nSubroutines share the same scope as the main program.\n\nIn no-linenumber mode, GOSUB can be used with label.\n\nSyntax:\n\n```\nGOSUB linenum\nRETURN\n\nGOSUB \"label\"\nRETURN \n```\n\nExample:\n\n```\n...\n20 GOSUB 110\n...\n100 END\n110 REM subrouting 1\n...\n200 RETURN\n```\n\n```\n...\nGOSUB \"sub1\"\n...\nEND\n\nLABEL \"sub1\"\n...\nRETURN\n```\n\n### User Defined Function or UDF\n\nA UDF executes an expression.\nThe UDF returns the result of the expression which is always a scalar.\nThe UDF can declare local scoped parameters.\nUDF can access variables from global scope.\nRecursive UDF is not supported.\n\nSyntax:\n\n```\nDEF variable(variables) = expr\n```\n\nThe variable name must start with 'FN' and may have a suffix to declare the return data type.\n\n\nExample:\n\n```\nDEF FNsquare%(X%) = X% * X%\n```\n\nThe above example computes the square of Int32 parameter X%.\n\n### More general User defined function\n\nA function is a UDF that can take any number of parameters and returns a single scalar value.\n\nThe function parameter are passed as follows:\n1. Scalar params are passed-by-value.\n1. Array/Composite params are passed-by-reference. \nNote that references themselves are copied.\nThe array dimensions must be declared using constants.\n\nA function has local scope, i.e. it cannot access variables declared outside the function.\n\nRecursive functions are not supported.\n\nSyntax:\n\n```\n' Define function\nFUNCTION funcname[varsuffix] (PARAMS) {\n    ...\n    RETURN expression\n}\n\n' Call function\nresult = funcname[varsuffix](VALUES)\n```\n\nExample:\n\n```\nFUNCTION fun1# (X, Y) {\n  IF Y = 0 THEN RETURN 0\n  Z = X / Y\n  RETURN Z\n}\n\nPRINT fun1#(2, 3)\n```\n\n### READ-DATA-RESTORE\n\nDATA keyword is used to define constant values.\nThe READ keyword is used to read the constant values sequentially.\nWhen all the values are read, the read cursor can be reset by using RESTORE statement.\n\nSyntax:\n\n```\nDATA constants\n...\nDATA constants\n\nREAD variables\nRESTORE\nREAD variables\n```\n\nExample:\n\n```\n10 DATA \"STRING\", 2, 5.2\n20 READ A$, B%, C#\n30 RESRORE\n40 READ A$, B%, C#\n```\n\n### Input Output\n\n#### PRINT\n\nPrint the expressions to standard out.\n\nSyntax:\n\n```\nPRINT expressions\n```\n\nThe expressions can be either separated by comma or semi-colon.\n\nExample:\n\n```\nPRINT \"AB\", 1, 2\nPRINT \"AB\"; 1; 2\nPRINT \"AB\", 1, 2,\n```\n\nIf there is no comma at the end of PRINT statement, a new-line is printed.\nIf there is a comma at the end of PRINT statement, no new-line is printed.\n\n#### PRINT USING\n\nFormats each expression using the given format and prints to standard out.\n\nSyntax:\n\n```\nPRINT USING format; expressions\n```\n\nThe format is a string expression.\n\n##### Formatting String expressions\n- '!' Prints the first character of each String expression.\n- '\u0026' Prints the entire String for each String expression.\n- '\\\\n spaces\\\\' Prints n+2 characters from each String expression.\n\n##### Formatting numeric expressions\n- '#' specifies 1 digit position.\n- '.' specifies decimal point.\n- ',' adds comma in formatted number.\n      \n###### First optional prefix:\n- '+' prefix will add a sign prefix.\n- '-' prefix will add a minus prefix for negative number.\n \n###### Next optional prefix:\n- '\\*\\*' causes leading spaces to be filled with '*' and specifies 2 more digit positions.\n- '\\*\\*$' adds dollar prefix, causes leading spaces to be filled with '*' and specifies 2 more digit positions.\n- '$$' add dollar prefix and specifies 1 more difit position.\n      \n###### First optional suffix:\n- '+' suffix will add a sign suffix.\n- '-' suffix will add a minus suffix for negative number.\n      \n###### Next optional suffix:\n- '^^^^' suffix indicates scientific notation.\n\nExamples:\n\n```\nPRINT USING \"\\ \\\"; \"123456\"; \"abcdef\"\nPRINT using \"###.##\"; 2.3\nPRINT using \"**###.##\"; 2.3\nPRINT using \"**$###.##\"; 2.3\n```\n\n#### WRITE\n\nPrints expressions on standard out.\nIt separates each expression with a comma.\nStrings are surrounded with double quotes.\n\n#### INPUT\n\nReads user input from standard in and assigns to variables.\n\nSyntax:\n\n```\nINPUT [prompt ;] variables\n```\n\nSince PuffinBASIC is platform independent, user must press ENTER to mark the end of input.\nAfter reading a line from standard in, INPUT will split the line using commas\ninto separate values (line a CSV line) and assign to each variable.\nIf the number of values don't match number of variables, the user will be\nasked to enter the values again.\n\nExample:\n\n```\nINPUT \"Enter two numbers: \"; A%, B%\n```\n\n#### LINE INPUT\n\nReads one line from standard in.\n\nSyntax:\n\n```\nLINE INPUT [prompt ;] stringVariable\n```\n\nExample:\n\n```\nLINE INPUT \"Enter a line: \"; A$\n```\n\n### File Handling\n\n#### Random Access Files\n\nRandom access file allows reading and writing data in fixed length records.\nThe default record length is 128.\n\nSyntax:\n\n```\nOPEN \"R\", #filenum, filename[, recordlen]\nOPEN filename FOR RANDOM AS #filenum LEN=recordlen\nFIELD#filenum, int as variable, int as variable, ...\nLSET variable = expr\n...\nPUT#filenum, recordnum\nGET#filenum, recordnum\nCLOSE#filenum\n```\n\nExample:\n\n```\n30 OPEN \"R\", #1, FILENAME$, 24\n40 FIELD#1, 8 AS A$, 8 AS B$, 8 AS C$\n50 FOR I% = 1 TO 5\n60 LSET A$ = MKI$(I%)\n70 LSET B$ = MKI$(I% + 1)\n80 LSET C$ = MKI$(I% + 2)\n90 PUT #1\n100 PRINT LOC(1), LOF(1)\n110 NEXT I%\n120 FOR I% = 1 TO 5\n130 GET #1, I% - 1\n140 PRINT A$, B$, C$, LOC(1), LOF(1)\n150 NEXT\n160 CLOSE\n```\n\n#### Sequential Access Files\n\nSyntax:\n\n```\nOPEN \"O\", #filenum, filename\nOPEN \"A\", #filenum, filename\nOPEN \"I\", #filenum, filename\n\nOPEN filename FOR OUTPUT AS #filenum\nOPEN filename FOR APPEND AS #filenum\nOPEN filename FOR INPUT AS #filenum\n\nWRITE#filenum, expr, expr, ...\nPRINT#filenum, expr, expr, ...\n\nCLOSE#filenum\n```\n\nWhen writing a sequential file, prefer using WRITE# over PRINT# statements.\n\nExample: Writing a sequential file\n\n```\n20 OPEN \"O\", #1, FILENAME$\n30 FOR I% = 1 TO 5\n40 WRITE#1, \"ABC\" + STR$(I%), 123 + I%, 456@ + I%, 1.2 + I%\n50 NEXT\n60 FOR I% = 1 TO 5\n70 PRINT#1, CHR$(34), \"ABC\" + STR$(I%), CHR$(34), \",\", 123 + I%, \",\", 456@ + I%, \",\", 1.2 + I%\n80 NEXT\n90 CLOSE #1\n```\n\nExample: Reading a sequential file\n\n```\n100 OPEN FILENAME$ FOR INPUT AS #1\n110 FOR I% = 1 TO 10\n120 INPUT#1, A$, B%, C@, D#\n130 PRINT A$, B%, C@, D#\n140 NEXT\n150 CLOSE\n```\n\n### DATE TIME\n\n#### DATE$\n\nSystem date can be read using DATE$ (like a variable).\nDate can be set to a String (for the duration of program only).\n\nSyntax:\n\n```\nv$ = DATE$\nDATE$ = \"YYYY-mm-dd\"\n```\n\n#### TIME$\n\nSystem time can be read using TIME$ (like a variable).\nTime can be set to a String (for the duration of program only).\n\n```\nTIME$ = \"HH:MM:SS\"\nv$ = TIME$\n```\n\n### MID$\n\n### RANDOMIZE\n\nSets the random seed.\n\nSyntax:\n\n```\nRANDOMIZE expr\nRANDOMIZE TIMER\n```\n\nThe expression is an Int64 expression.\nTIMER uses the current time in seconds.\n\nExample:\n\n```\nRANDOMIZE 1002\n```\n\n### SLEEP\n\nSleep for given number of milliseconds.\n\nSyntax:\n\n```\nSLEEP n\n```\n\n## ARRAY\n\n### ARRAYFILL\n\nFill an n-dimensional array with the given value.\n\nSyntax:\n\n``\nARRAYFILL arrayvariable, value\n``\n\nExample:\n\n```\nARRAYFILL A%, 10\n```\n\n### ARRAYCOPY\n\nCopy values in source array variable to values in destination array variable.\nThe data types and total number of elements in the array variables must match.\n\nSyntax:\n\n``\nARRAYCOPY srcarrayvariable, dstarrayvariable\n``\n\nExample:\n\n```\nARRAYFILL A%, B%\n```\n\n### ARRAY1DCOPY\n\nCopy value from source array variable to destination array variable.\nBoth must be 1D array.\n\nsrcOrigin is from where to start copy in the source.\ndstOrigin is to where to start copy in the destination.\nlengthToCopy is the number of elements to copy.\n\nSyntax:\n\n```\nARRAY1DCOPY srcvariable, srcOrigin, dstvariable, dstOrigin, lengthToCopy\n```\n\nExample:\n\n```\nARRAY1DCOPY F%, 1, F%, 3, 2\n```\n\n### ARRAY1DSORT\n\nSorts (in-place) the values in the given 1-dimensional array variable.\n\nSyntax:\n\n``\nARRAY1DSORT arrayvariable\n``\n\nExample:\n\n```\nARRAY1DSORT A%\n```\n\n### ARRAY2DSHIFTVER\n\nShift rows up or down by given n rows in the given 2D array.\nThe empty space (rows) is filled with 0 or empty string.\nn \u003e= 0 means shift rows down.\nn \u003c 0 means shift rows up.\nThis is a very efficient operation.\n\nSyntax:\n\n```\nARRAY2DSHIFTVER arrayvariable, n\n```\n\nExample:\n\n```\nARRAY2DSHIFTVER D%, 2\nARRAY2DSHIFTVER D%, -3\n```\n\n### ARRAY2DSHIFTHOR\n\nShift columns up or down by given n columns in the given 2D array.\nThe empty space (columns) is filled with 0 or empty string.\nn \u003e= 0 means shift columns down.\nn \u003c 0 means shift columns up.\nThis operation should be faster than doing it with loops, but not as efficient as ARRAY2DSHIFTVER.\n\nSyntax:\n\n```\nARRAY2DSHIFTHOR arrayvariable, n\n```\n\nExample:\n\n```\nARRAY2DSHIFTHOR D%, 2\nARRAY2DSHIFTHOR D%, -3\n```\n\n## Graphics\n\nUse '--graphics' or '-g' to enable graphics mode.\n\n### SCREEN\n\nCreate a window with the title and a drawing canvas of size wxh (width x height).\nThe window is not resizable.\nTop left of the drawing canvas is 0,0 and bottom right is w,h.\nIf MANUALREPAINT is set, the drawing canvas is not repainted automatically,\nand REPAINT must be invoked manually (and periodically in a game loop).\n\nSyntax:\n\n```\nSCREEN title$, w, h[, MANUALREPAINT]\n```\n\nExample:\n\n```\nSCREEN \"PuffinBASIC 2D Graphics\", 800, 600\n```\n\n### COLOR\n\nSets foreground color in the graphics context\nusing red, green and blue color components.\nEach color component is an Int32 ranging from 0 to 255.\n\nSyntax:\n\n```\nCOLOR r, g, b\n```\n\nExample:\n\n```\nCOLOR 0, 255, 0\n```\n\n### FONT\n\nSets the font name with given options and font size.\noptions$ is a String: \"i\" means Italic, \"b\" means bold. \nMultiple options can be combined into a String.\n\nSyntax:\n\n```\nFONT name$, options$, size\n```\n\nExample:\n\n```\nFONT \"Georgia\", \"bi\", 50\n```\n\n### DRAWSTR\n\nDraws the given string at given position on the drawing canvas.\n\nSyntax:\n\n```\nDRAWSTR text$, x, y\n```\n\nExample:\n\n```\nDRAWSTR \"SAMPLE Text\", 100, 400\n```\n\n### PSET\n\nDraws a point on the given position.\nAn optional color can be specified.\nIf no color is specified, color is picked from the graphics context.\n\nSyntax:\n\n```\nPSET (x, y) [, r, g, b]\n```\n\nExample:\n\n```\nPSET (100, 100)\n```\n\n### CIRCLE\n\nDraws an oval at position x, y with radii of r1 and r2.\nIf start angle (degrees) and end angle (degrees) are specified,\nan arc is draw (clockwise).\nTo fill the circl with foreground color, set options as \"F\".\n\nSyntax:\n\n```\nCIRCLE (x, y), r1, r2[, start_angle?, end_angle?[, options]]\n```\n\nExample:\n\n```\nCIRCLE (100, 200), 50, 50\nCIRCLE (100, 200), 50, 50, 0, 90\nCIRCLE (100, 200), 50, 50, 90, 180, \"F\"\n```\n\n### LINE\n\nDraw a line from position1 (x1, y1) to position2 (x2, y2).\nOptions can be \"B\" or \"BF\".\nIf \"B\" is used, a box is drawn.\nIf \"BF\" is used, a filled box is drawn.\n\nSyntax:\n\n```\nLINE (x1, y1) - (x2, y2) [, options]\n```\n\nExample:\n\n```\nLINE (0, 0) - (10, 10), \"BF\"\n```\n\n### PAINT\n\nFlood fills the drawing canvas starting at the given position with foreground color\nuntil the given color boundary is hit.\nFlood fill has no effect if called on a point which already has foreground color.\nPAINT is a slow operation.\nPrefer filling the shapes using \"F\" option.\n\nSyntax:\n\n```\nPAINT (x, y), border_r, border_g, border_b\n```\n\nExample:\n\n```\nPAINT (155, 155), 255, 255, 255\n```\n\n### DRAW\n\nDraw an arbitrary path. \nThe path starts at middle of the screen.\n\nFollowing instructions are supported:\n```\nUn:   up n pixels\nDn:   down n pixels\nLn:   left n pixels\nRn:   right n pixels\nEn:   (diagonal) up and right n pixels each\nFn:   (diagonal) down and right n pixels each\nGn:   (diagonal) down and left n pixels each\nHn:   (diagonal) up and left n pixels each\nB:    pen up (i.e. move only);\n        it can be added to any of above instructions.\nN:    return to original position after drawing; \n        can be added to any of above instructions.\nMx,y: move to x,y (absolute or relative). \n        If x and y have +/- prefix, \n        move is relative to curren position, \n        otherwise, move is to absolute position.\n```\nThe instructions are separated by a semi-colon.\n\nSyntax:\n\n```\nDRAW path$\n```\n\nExample:\n\n```\nDRAW \"U30; E30; R30; F30; DNB30; R30; M+30,+30; R30; R50\"\n```\n\n### GET\n\nCopy drawing canvas contents from x1,y1 to x2,y2 to given array variable.\nThe variable must be of Int32 type.\nThe array dimensions must match x2-x1,y2-y1.\nx1,y1 is inclusive.\nx2,y2 is exclusive.\n\nx1,y1 and x2,y2 must be within the bounds of the drawing canvas.\n\nSyntax:\n\n```\nGET (x1, y2) - (x2, y2), variable\n```\n\nExample:\n\n```\nDIM A%(32, 32)\nGET (0, 0) - (32, 32), A%\n```\n\n### PUT\n\nCopy array variable contents to the drawing canvas at x,y position.\nThe variable must be of Int32 type.\nx,y must be within the bounds of the drawing canvas.\n\nMode can be XOR, OR, AND, PSET (overwrite), and MIX (overwrite opaque parts only).\n\nSyntax:\n\n```\nPUT (x, y), variable[, mode]\n```\n\nExample:\n\n```\nDIM A%(32, 32)\nGET (0, 0) - (32, 32), A%\nPUT (100, 100), A%\n```\n\n### LOADIMG\n\nLoad an image into the given array variable.\nThe variable must be of Int32 type.\nThe array dimensions must match the image dimensions.\nCommon formats such as png, jpeg, gif, bmp are supported.\n\nSyntax:\n\n```\nLOADIMG image, variable\n```\n\nExample:\n\n```\nDIM A%(32, 32)\nLOADIMG \"enemy1.png\", A%\n```\n\n### SAVEIMG\n\nSave an image from the given array variable.\nThe variable must be of Int32 type.\nCommon formats such as png, jpeg, gif, bmp are supported.\n\nSyntax:\n\n```\nSAVEIMG image, variable\n```\n\nExample:\n\n```\nDIM A%(32, 32)\n...\nSAVEIMG \"enemy1.png\", A%\n```\n\n### INKEY$\n\nRead one key pressed on keyboard.\n\nASCII characters are returned as single byte Strings.\n\nSpecial characters, e.g. UP arrow, DOWN arrow, \nare returned as two byte String - the first byte is always byte 0.\n\nSpecial Key Codes:\n```\nLEFT arrow:  CHR$(0) + CHR$(37)\nUP arrow:    CHR$(0) + CHR$(38)\nRIGHT arrow: CHR$(0) + CHR$(39)\nDOWN arrow:  CHR$(0) + CHR$(40)\n```\n\nSyntax:\n\n```\nINKEY$\n```\n\nExample:\n\n```\nK$ = INKEY$\n\n' Check Up Arrow\nIF K$ = CHR$(0) + CHR$(38) THEN y2% = y% - 5\n```\n\n### CLS\n\nClear the screen.\n\nSyntax:\n\n```\nCLS\n```\n\n### BEEP\n\nMake a beeps sound.\n\nSyntax:\n\n```\nBEEP\n```\n\n### REPAINT\n\nRepaint the drawing canvas. Use this when automatic repaint is off.\n\nSyntax:\n\n```\nREPAINT\n```\n\n### LOADWAV\n\nLoad sound (wav) file.\n\nSyntax:\n\n```\nLOADWAV path, variable\n```\n\n### PLAYWAV\n\nPlay sound, loaded earlier via the LOADWAV statement.\n\nSyntax:\n\n```\nPLAYWAV variable\n```\n\n### STOPWAV\n\nStop the playing sound.\n\nSyntax:\n\n```\nSTOPWAV variable\n```\n\n### LOOPWAV\n\nLoop (continuously) the sound, loaded earlier via the LOADWAV statement.\n\nSyntax:\n\n```\nLOOPWAV variable\n```\n","funding_links":[],"categories":["Dialects"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmayuropensource%2FPuffinBASIC","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmayuropensource%2FPuffinBASIC","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmayuropensource%2FPuffinBASIC/lists"}