mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 20:33:39 +00:00
89 lines
5.4 KiB
ReStructuredText
89 lines
5.4 KiB
ReStructuredText
.. _comparingprog8:
|
|
|
|
============================
|
|
Prog8 versus other languages
|
|
============================
|
|
|
|
This chapter is meant for new Prog8 users coming with existing knowledge in another programming language such as C or Python.
|
|
It discusses some key design aspects of Prog8 and how it differs from what you may know from those languages.
|
|
|
|
|
|
The language
|
|
------------
|
|
- Prog8 is a structured imperative programming language. It looks like a mix of Python and C.
|
|
- It is meant to sit well above low level assembly code, but still allows that low level access to the system it runs on.
|
|
Via language features, or even simply by using inline hand-written assembly code.
|
|
- Identifiers and string literals can contain non-ASCII characters so for example ``knäckebröd`` and ``見せしめ`` are valid identifiers.
|
|
|
|
No linker
|
|
---------
|
|
- Even though your programs can consist of many separate module files, the compiler always outputs a single program file. There is no separate linker step.
|
|
Currently, it's not easily possible to integrate object files created elsewhere.
|
|
- The prog8 compiler is self-contained in a single jar file. You do need 1 external tool namely 64tass, which performs the assembler step.
|
|
|
|
|
|
Data types
|
|
----------
|
|
- There are byte, word (16 bits) and float datatypes for numbers). There are no bigger integer types natively available.
|
|
- There is no automatic type enlargement: calculations remain within the data type of the operands. Any overflow silently wraps or truncates.
|
|
You'll have to add explicit casts to increase the size of the value if required.
|
|
For example when adding two byte variables having values 100 and 200, the result won't be 300, because that doesn't fit in a byte. It will be 44.
|
|
You'll have to cast one or both of the *operands* to a word type first if you want to accomodate the actual result value of 300.
|
|
|
|
|
|
Variables
|
|
---------
|
|
- There is no dynamic memory management in the language; all variables are statically allocated.
|
|
(but user written libraries are possible that provide that indirectly).
|
|
- Variables can be declared everywhere inside the code but all variable declarations in a subroutine
|
|
are moved to the top of the subroutine. A for loop, or if/else blocks do not introduce a new scope.
|
|
- All variables are initialized at the start of the program. There is no random garbage in them: they are zero or any other initialization value you provide.
|
|
- This als means you can run a Prog8 program multiple times without having to reload it from disk, unlike programs produced by most other compilers targeting these 8 bit platforms.
|
|
|
|
|
|
Subroutines
|
|
-----------
|
|
- There is no function overloading (except for a couple of builtin functions).
|
|
- Some subroutine types can return multiple return values, and you can multi-assign those in a single statement.
|
|
- Because every declared variable allocates some memory, it might be beneficial to share the same variables over different subroutines
|
|
instead of defining the same sort of variables in every subroutine.
|
|
This reduces the memory needed for variables. A convenient way to do this is by using nested subroutines - these can easily access the
|
|
variables declared in their parent subroutine(s).
|
|
- Everything in prog8 is publicly accessible from everywhere else (via fully scoped names) - there is no notion of private or public symbol accessibility.
|
|
|
|
|
|
Pointers
|
|
--------
|
|
- There is no specific pointer datatype.
|
|
There *are* pointers however, in the form of the `uword` datatype. This can be used to point to one of the possible 65536 memory locations,
|
|
so the value it points to is always a single byte. You have to reinterpret it manually if the object it points to is something different.
|
|
|
|
|
|
Strings and Arrays
|
|
------------------
|
|
- these are allocated once, statically, and never resized.
|
|
- they are mutable: you can change their contents, but always keep the original storage size in mind to avoid overwriting memory outside of the buffer.
|
|
|
|
|
|
Foreign function interface (external/ROM calls)
|
|
-----------------------------------------------
|
|
- You can use the ``romsub`` keyword to define the call signature of foreign functions (usually ROM routines, hence the name) in a natural way.
|
|
Calling those generates code that is as efficient or even more efficient as calling regular subroutines.
|
|
No additional stubs are needed. (unless there is bank switching going on, but this *may* be improved in a future language version)
|
|
|
|
Optimizations
|
|
-------------
|
|
- Prog8 contains many compiler optimizations to generate efficent code, but also lacks many optimizations that modern compilers do have.
|
|
While empirical evidence shows that Prog8 generates more efficent code than some C compilers that also target the same 8 bit systems,
|
|
it still is limited in how sophisticated the optimizations are that it performs on your code.
|
|
- For time critical code, it may be worth it to inspect the generated assembly code to see if you could write things differently
|
|
to help the compiler generate more efficient code (or even replace it with hand written inline assembly altogether).
|
|
For example, if you repeat an expression multiple times it will be evaluated every time, so maybe you should store it
|
|
in a variable instead and reuse that variable::
|
|
|
|
if board[i+1]==col or board[i+1]-j==col-row or board[i+1]+j==col+row {
|
|
...do something...
|
|
}
|
|
|
|
In this example, consider storing ``board[i+1]`` in a variable first and reuse that in the expression instead.
|