Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - bas

Pages: [1] 2 3
Ideas / Struct Function declaration
« on: April 15, 2017, 09:22:04 PM »
With the current syntax, I think it's quite unclear when a function is a struct function. I would
like to try to make this more explicit. So hereby some ideas.

Code: [Select]
func void point_add(Point* p, int32 x) { .. }    // current syntax

func void Point_add(Point* p, int32 x) { .. }   // allow Upper-case as first char, so looks more like type Point

func void point_add[Point](Point* p, int32 x) { ..} /// hmm, 3 points in a

func void point_add(Point* p, int32 x) @{structfunc} { ..} // via attribute
func void point_add(Point* p, int32 x) @{struct='Point'} { ..} // via attribute, nr 2

func void Point.add(Point* p, int32 x) { .. }   // most explicit, via member operator


I like the last option best. The two arguments against it are:
  • it's harder to see what the c- function name is (point_add in all cases). The is actually currently
        the same for module attributes as well ( -> foo_bar)
  • The syntax breaks more with the ansiC style

What do you think?

Ideas / Struct Functions - part 2
« on: November 28, 2016, 09:08:33 AM »
I've been implementing some code using struct functions and must say I'm completely happy with the calling side. On the receiving side (the function itself), a patterns is appearing that might be avoided. Currently struct functions look like this:

Code: [Select]
func void myStruct_init(MyStruct* this) {
   this.a = 1;
   this.b = 2;
   // ..

This is just a small piece of code, but the thing that starts to itch in bigger functions is the frequent appearance of the this.
To make it feel more like (for example) a C++ class, we could add the struct members in the function namespace. Then all the
this keywords could go (unless ambiguous). This would have some consequences:

  • name duplicates between module and struct members is allowed (since can distinguish with module.a and this.a)
  • name duplication between struct members and function arguments is not allowed (cannot distinguish somehow)

I don't think since is a problem, since it's not a problem in object-oriented languages as well. Any feedback is welcome,


General Discussion / Light-weight classes
« on: April 28, 2016, 09:38:34 PM »
There was recently a discussion on (
On of the often heard ideas was C++, but without all the fluff. But something like lightweight classes.

C++ has (multiple)inheritance, no real interfaces (like Java), operator overloading, method overloading etc etc
If you just want the basics, eg a struct with functions, that should be possible to create. It's just syntactic sugar,
Code: [Select]
func void MyStruct::myfunction() {..}
just becomes:
Code: [Select]
func void myfunction(MyStruct* A) {..}

Of course, when you also want interfaces, it becomes harder.
And when you also want to use the same function name with different parameter types, it again becomes harder..

My conclusion is that any 'lightweight' class construction will quickly lead to a lot of fluff, because people except
all those features in languages with classes. So it might just be easier to just leave them out altogether...

General Discussion / Pthreads
« on: November 20, 2015, 09:49:30 PM »
Now that library support is in place, I've been trying out pthreads. This is quite a weird library it seems.
On OS X, compilation doesn't need a special linker flag. If you pass '-pthread', clang gives a warning about
'unused flag'. On linux, clang needs '-pthread' to build, otherwise you get an 'undefined reference to..' warning.


Ideas / Enum classes
« on: July 20, 2015, 04:43:25 PM »
Recently C++11 introduced the concept of enum classes. This puts the enum constants
in their own enum's namespace. So:

Code: [Select]
enum class State {

This allows the compiler to detect clashes between different enums and some other tricks. A second advantage
is avoiding name clashes between the MIDDLE of one enum type with MIDDLE of the second enum type.

In C2 there are already modules to avoid clashes, but currently the enum constants (like START, MIDDLE, etc)
end up in that modules namespace. I'm toying with the idea to always put enum constants in their own namespace.
The declaration will still look exactly the same, but the usage now uses an enum namespace, like

Code: [Select]
module test;

type State enum int32 {

func void foo() {
   State s1 = Start;               // current situation (full: test.Start)
   State s2 = State::Start;     // option 1 (full: test.State::Start)
   State s3 = State.Start;      // option 2 (full: test.State.Start)


Note that the module member operator is already a dot (.). I prefer test.State::Start over
test.State.Start, since it distinguishes the enum namespace and a.b is always either a module
or struct member. Once again I look for the experience and wisdom of the forum members :)

General Discussion / Modules
« on: May 04, 2015, 11:41:09 AM »
The default C/C++ language communities are gaining momentum to fix the Header file problem.
Here is another interesting proposal for Modules in C++:

What I noticed was that they also state macro's as a big problem and also use the word Evolution.
So more indications we're moving in the right direction  :D

There are some differences howevery:
  • In C2, you can choose which declarations to export outside the source (in the recipe file)
  • The paper exports all symbols put in the module, C2 distinguishes between public in a Module and exporting from the compilation unit
  • The paper proposal sub-modules, while C2 only allows a single layer to avoid having to mangle the symbols
  • In C2 you only type-once, so no forward decls, etc. The paper requires exporting the symbol, separate from defining it.

General Discussion / Another programming language initiative
« on: April 19, 2015, 09:11:48 PM »
I recently came across a lot of videos by Jonathan Blow, a game designer/developer who's
apparantly designing a language specifically for game programming. It seems to be called Jai.

if you have time (20+ hours on video... 8) )

Ideas / one big design item: Macros
« on: April 11, 2015, 10:27:17 PM »
One of the big remaining design issues (next to countless smaller ones  :) ) is the design
of a new macro system that is not based on textual substitution by the preprocessor.

Let's start by looking at the goal of macros:
  • Feature selection
Code: [Select]
  • Constants
Code: [Select]
#define MAX_ITEMS 10
  • code expansion
Code: [Select]
#define print_if_positive(x) \
   if (x > 0) printf("value is %d\n", x);

I think each of these is a valid goal. So the new macro system should provide
a solution for each (in some way or another). For the Feature selection, C2 can
use the same way as C; since the C2 compiler also has a preprocessor, it's completely

The Constants goals is attained in C2 by using const of Numeric types:
Code: [Select]
const int32 MAX_ITEMS = 10;This will just 'replace' all references with 10.

The Code-expansion is the hardest. Since there is no textual replacement, the macro system
has to be language aware. This means that when parsing the macro definition, the parser must
understand what's happening. This results in 2 types of macros: local and non-local. Local macros
can be used inside functions, while non-local macros can only be used outside function
bodies. So local macros are parsed as a series of Statements, while non-local macros are parsed
as a list of global declarations.

The syntax I currently think of is:
Code: [Select]
local macro(x) {
   io.printf("value of "$$x" = %d", x);
macro(x) {
func gen_$x() {

Open issues:
  • Q: are public macros in module X allowed to access non-public Decls in X?
  • Q: what to allow as macro arguments?
  • Q: what syntax to use for argument replacement, concatenation and stringify?

Implementation Details / Milestone reached!
« on: March 06, 2015, 10:26:41 PM »
C2 just reached another milestone: completely building a (static) library and genarting the c header file!   ;D
The library itself is created by generating c-files and a makefile and then running the makefile. This is of course not the final path, but will definately help in fleshing out more details. Also I extended the unit-test framework to test generated C files easily.

One detail that came up was the name 'mangling'. The generated names of module.decl used to be __module_decl. But the linker couldn't find these in the static library. So the mangling now just consists of module_decl, also a bit easier on the eyes.

The next step will be playing with the options to control object visibility.

Ideas / Array types
« on: January 20, 2015, 09:29:42 AM »
I recently read
where the author states that the (one of) the biggest mistakes made in C was
converting an array to a pointer when calling a function, so (C-code)
Code: [Select]
int array[4];
int* ip = &array[0];
the two calls are equal. One idea would be to make this distinction. One limit would be
that the array would be a known size (in function prototype), eg (C2 code)
Code: [Select]
func void setMacnr(char[4] macnr) { .. }
A function that would take a variable sized array (like string functions) would still require a pointer and a size

Implementation Details / BitOffsets
« on: December 04, 2014, 08:11:44 PM »

I've just pushed a new feature called BitOffsets. This allows easy copying of certain bit-ranges, like often
done in drivers. So if your chip's reference guide says:   Counter Bit 14-10, you used to do (in Plain-Old-C)

Code: [Select]
int counter = ((value >> 10) & 0x1F);
Which is not too readable. Off course you could use a fancy macro like REG_BITS(value, 10, 0x1F),
but that's not really nice either.

Because C2 targets kernels, bootloaders and other low-level programs, accessing register values should
be easy. Enters BitOffsets:

Code: [Select]
int counter = value[14:10];
Which does the same as the example above. Additionally it can check possible overflows (like assigned a 8+ width
value to a char etc)

Currently BitOffsets can only be used in RHS (Right-hand side) expressions. I'm still debating whether
to also allow this on LHS expressions.

Ideas / Big Renames
« on: June 03, 2014, 02:15:29 PM »
After a lot of thinking, I've decided to finally rename package -> module and use -> import.
A module is more a part of something bigger, while a package has something complete in
the name. Also it conforms to a lot of new generation languages.

Implementation Details / Update from LLVM 3.3 -> 3.4
« on: May 21, 2014, 08:32:00 PM »

Upgrading from Clang/LLVM 3.3 to the latest 3.4 has been on the TODO list for a while, but has been
pushed minutes ago. The nasty part was that I had to manually compile GCC 4.8.2 on Ubuntu 12.04
32-bit (my laptop) to get to compile LLVM/Clang at all. On my desktop (Arch 64 bit, GCC 4.9.x), I
required some testing. The upgrade was a lot less work then the 3.2 -> 3.3 upgrade, so maybe the
Clang internal API seems to be stabilizing as well..

Today I've pushed the functionality to let the C2 compiler generate the full dependency graph for a project.
The output is in XML form and shows types, (global)variables and functions and their complete relationship.
Also the containing package is show and optionally the file they're in. (yes functions are in a single file! no
header/c-file issues here  :) )

To show how this works, I've analysed the puzzle.c2 example (
The resulting architecture is show in
Then I refactored it, by extracting some functions/vars into a separate file (really easy, just move them to
a new file, add that to recipe and done). This results in

While the example is very small, it already starts showing the potential of the language/tools.
The next step will be to integrate these into c2reto (C2 refactor tool), so that drag-n-drop refactoring
and continuous visualization is possible. I can't wait to see how that works out!

Implementation Details / update wk17
« on: April 23, 2014, 08:29:28 PM »

Current progress on the C2 compiler has focused on the Analyser. Currently there are
over 250 unit tests to make sure it keeps working. Not an easy thing. Recently I've
added some checks for array initializations. While I've been programming C for a long
time, I've never realized just how many details there are to a compiler. Some situations:

    int[]   a;    // @error{definition of variable with array type needs an explicit size or an initializer}
    char[] b;   // @error{definition of variable with array type needs an explicit size or an initializer}

    int[]   c = 10;  // @error{array initializer must be an initializer list}
    char[]  d = 20;  // @error{array initializer must be an initializer list or string literal}
    uint8[] e = 20;  // @error{array initializer must be an initializer list or string literal}

    int[]   f = "foo"; // @error{array initializer must be an initializer list}
    char[]  g = "bar";
    uint8[] h = "faa";

    char[3] i = "bar";
    char[3] j = "hello"; // @error{initializer-string for char array is too long}

and that's just a tiny part.
But with a *Lot* of small steps, we're getting there. Slowly more and more situations
are being handled. While C2 is still a far way from being a full fledged C alternative,
the Analyser part is definitely showing it's advantages over gcc/clang. Getting warnings
about unused struct fields and unused types is very nice!

Hopefully the next update won't take as long as this one...


Pages: [1] 2 3