You are browsing as a guest. Sign up (or log in) to start making projects!

DotC

  • 3 Devlogs
  • 18 Total hours

DotC is a C compiler and the reference implementation of a runtime-interop standard. It's built on the Idea that no matter what runtime you're in, C is always at the end of the dot.

Open comments for this post

3h 31m 15s logged

The ENUM has entered the chat and well did a bit of cleanup + better console system. But just as a quick question how have y’all been doing on your projects? Also what keyword should I add next? Well enough of a rant let me really talk now:

Added the enum keyword to the lexer reserved word list. On the paper side, EnumDecl AST nodes got built and registered in a new EnumRegistry that tracks member->value mappings. Simultaneously, operators tokens were unified into a single TokenKind.Operator with a seperate C# enum called OperatorKind that maps to all the operators.

Fixed != parsing, unsigned comparison codegen, enum member overflow, bare unsigned keyword ussage, and duplicate enum member detection.

Now alongside enum I also added typedef. It supports both the simple typedef <type> <alias> and typedef enum { ... } <alias> forms.

Now I was talking about the EnumRegistry and the other one was TypeAliasREgistry, but to make it more maintainable I unifed it all under a generic NameRegistry<T> base.
I did a lot of cleanup on the parser project that I’m not really go into because it’s a bit pointless.

I overhauled the diagnostic system alongisde just the CLI. I moved from System.CommandLine to Spectre.Console.Cli.

Now the most recent thing was the diagnostic system when it comes to multiple errors. I replaced Pidgin’s combinator-based recovery with custom Parser<TToken, T> subclasses.
I added a RecoverableList that tries to parse each item, on failure it reports the error, skips the offending token, and advances to the next ; before retrying.
And a few other things such as dropping AOT because of reflection and keeping R2R, SingleFile, and selfcontained.

And if you look at the images you can see the new diagnostic system and the typedef and enum keyword working,and working together.

0
0
35
Open comments for this post

4h 19m 49s logged

So it’s been a day or 2 since the last devlog, but I’ve been on vacation and just been a little busy with life, anyhow enough of a rant.

This devlog goes over what I’ve added; that being: while loops, char and unsigned integer types, signed and unsigned aware comparison codegen, and a bit of better cross-platform toolchain support.

while loops were implemented E2E. The lexer recongizes the while keyword, a new WhileStatement AST node holds the info, and the parser backing it. Now the codegen emits the loop as a loopTop label, a conditional branch via the existing infra, the body statements, and a jmp loopTop.

Now keep in mind this is basically a debug build, but now let’s say you have this C code:

int main() 
{
   char x = 0;
   while (x < 15) 
   {
       x = x + 1;
   }
   return x;
}

To keep it bluntly this is the ASM:

_TEXT SEGMENT

main PROC
    push rbp
    mov  rbp, rsp
    sub  rsp, 16
    mov  eax, 0
    mov  byte ptr [rbp-8], al
@while_top0:
    cmp  byte ptr [rbp-8], 15
    jge  @while_end2
@while_body1:
    movsx eax, byte ptr [rbp-8]
    add  eax, 1
    mov  byte ptr [rbp-8], al
    jmp  @while_top0
@while_end2:
    movsx eax, byte ptr [rbp-8]
    mov  rsp, rbp
    pop  rbp
    ret
main ENDP

_TEXT ENDS

END

But if you want an explanation:
Now I’m going to skip the setting up the stack frame, but baically the first few instrctions setup the stack frame and reserve 16 bytes.

Now you see we have a variable x which is a char. Now a char on x64 is 1 byte. So that’s what this does:

mov  eax, 0
mov  byte ptr [rbp-8], al

We zero it out and then store the low byte (al) into x‘s stack slot. Now that’s cool and all, but what about the while loop!!

Well before we can do anything we have a condition: x < 15 or while (x < 15) and that is the part of the @while_top0.

@while_top0:
    cmp  byte ptr [rbp-8], 15
    jge  @while_end2

We take x and compare it directly against 15 as a byte and jumps out of the loop if x >= 15.

Now what about the body? Well the body (x = x + 1;) gets evaluated in this body:

@while_body1:
    movsx eax, byte ptr [rbp-8]
    add  eax, 1
    mov  byte ptr [rbp-8], al
    jmp  @while_top0

This code loads x, sign-extending it into a full 32-bit eax which is needed because arithmetic promotes char to int in C. It adds 1, then truncates back down to a byte when storing into x. Then it jumps back to re-check the condition.

What about the end? Well this:

@while_end2:
    movsx eax, byte ptr [rbp-8]
    mov  rsp, rbp
    pop  rbp
    ret

Now this sign-extends x into eax one more time as the return value, tears down the frame, and returns.

Now unsigned works, but uhh that’s a lot of instructions, but yeah this is DotC with a while. Now the cross-platform system it mainly reliant on Wine as this compiler only really emits MASM for right now and it requires kernel32.lib… so maybe in the future.

And to my Linux people: yes, that is PowerShell, not Bash, and also it’s Kitty.

And to my .NET people: yeah I’m using VSCode over Rider on Linux. it’s just lighter weight and I really don’t need a full IDE at the moment.

0
0
79
Open comments for this post

10h 10m 6s logged

So, my last C compiler I forgot to install Wakatime 😅, so this is a revamp of the last C compiler, but I’m applying some knowledge to this one.

Now I kicked the whole thing off with a few different C# projects and scaffolded. The libraries I chose for this project are Pidgin, System.CommandLine, and Serilog.

For my first commit I already had some work done, but it was 3.6k LOC across 64 files and it had a working lexer with keyword/punctuator recognition and trivia handling. It had a recursive-descent parser with expression parsing, statement parsing, and declaration parsing. I had AST node types as C# records for expressions, operators, and statements with x86 MASM code generation with expression and statement lowering and a symbol table. I had a CLI with a few different flags and what not. And quite a few unit tests (generated by my pookie Claude) and yeah.

Now a little later(yesterday) I added if/else control flow with a IfStatement AST node with all sorts of things and else keyword and all sorts of things. Added a semantic analyzer to validate if-statement conditions and Boolean compat. Now last night I did have Claude go through and add some unit tests and cleanup the codebase, so removing unused using statements and cleanup the parser and remove warnings. Also orchestrated it to refactor a bit of the parser into a few different files instead of one big file and had it fix an issue with a diagnostic code being reused that was–well–wrong.

Now I will say the biggest pain in my butt has been naming conflicts with Pidgin, but that’s not too bad.

2
0
49

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…