C compiler

This page describes the design of the C compiler. If you want to use the compiler, please see ppci-cc or ppci.api.cc().


digraph x {
codegen [label="code generator" ]
source -> lexer [label="text"]
lexer -> preprocessor [label="tokens"]
preprocessor -> parser [label="tokens"]
preprocessor -> source [label="include"]
parser -> semantics [label="callback functions"]
semantics -> scope
semantics -> codegen [label="parsed program (AST)"]

The C compilers task is to take C code, and produce intermediate code for the backend. The first step is pre processing, during which a sequence of tokens is transformed into another sequence of tokens. Next comes parsing and code generation. There are two options here: split the parser and code generation passes, such that there is a clean seperation, or do it all at once. Maybe the best choice is to do it all in one pass, and transform a sequence of tokens into IR-code in a single go.


The preprocessor is a strange thing. It must handle trigraphs, backslash newlines and macros.

The top level design of the preprocessor is the following:

  • Context: Contains state that would be global otherwise.
  • CLexer: processes a raw file into a sequence of tokens
  • Preprocessor: takes the token sequence a does macro expansion, resulting in another stream of tokens.
  • Output: The token stream maybe outputted to file.
  • Feed to compiler: The token stream might be fed into the rest of the compiler.

C compiler

The c compiler consists of the classical stages: parsing and codegeneration. Code generation is done to ir-code.


The C parsing is done by two classes CParser and CSemantics. CParser is a recursive descent parser. It dances a tight dance with the CSemantics class. This idea is taken from the Clang project. The CParser takes a token sequence from the preprocessor and matches the C syntax. Whenever a valid C construct is found, it calls the corresponding function on the CSemantics class. The semantics class keeps track of the current scope and records the global declarations. It also check types and lvalues of expressions. At the end of parsing and this type checking, an abstract syntax tree (AST) is build up. This AST is type checked and variables are resolved. This AST can be used for several purposes, for example static code analysis or style checking. It is also possible to generate C code again from this AST.


The semantics class determines for each expression node whether it is an lvalue or not. The lvalue (short for location value) indicates whether the expression has a memory address, or is a value in a register. Basically it boils down to: can we take the address of this expression with the ‘&’ operator. Numeric literals and the results of addition are not lvalues. Variables are lvalues. The lvalue property is used during code generation to check whether the value must be loaded from memory or not.


Hosted vs freestanding

A C compiler can be hosted or freestanding. The difference between those two is that a hosted C compiler also provides the standard C library. A freestanding compiler only contains a few really required header files. As a result a hosted compiler is really a combination of a C compiler and a C standard library implementation. Also, the standard library depends on the operating system which is used, where as a freestanding C compiler can be used independent of operating system. Writing an application using a hosted compiler is easier since the standard library is available.

digraph x {
  hosted [label="Hosted C application"]
  freestanding [label="Freestanding C application"]
  os [label="Operating system"]
  libc [label="C standard library"]
  compiler [label="C compiler"]
  hosted -> libc
  freestanding -> compiler
  libc -> os
  libc -> compiler

Code generation

Code generation takes the AST as a whole and loops over all its elements and generates the corresponding IR-code snippets from it. At the end of code generation, there is an IR module which can be feed into the optimizers or code generators.

C classes

The C frontend can be used to generate an AST from C code. You can use it to parse C code and analyze its structure like this:

>>> from ppci.api import get_arch
>>> from ppci.lang.c import create_ast
>>> src = "int a, *b;"
>>> ast = create_ast(src, get_arch('msp430').info)
>>> ast
Compilation unit with 2 declarations
>>> from ppci.lang.c import CAstPrinter
>>> printer = CAstPrinter()
>>> printer.print(ast)
Compilation unit with 2 declarations
    Variable [storage=None typ=Basic type int name=a]
        Basic type int
    Variable [storage=None typ=Pointer-type name=b]
            Basic type int
>>> ast.declarations[0].name

Module reference

C front end.

ppci.lang.c.create_ast(src, arch_info, filename='<snippet>', coptions=None)

Create a C ast from the given source

ppci.lang.c.preprocess(f, output_file, coptions=None)

Pre-process a file into the other file.

ppci.lang.c.c_to_ir(source: io.TextIOBase, march, coptions=None, reporter=None)

C to ir translation.

  • source (file-like object) – The C source to compile.
  • march (str) – The targetted architecture.
  • coptions – C specific compilation options.

An ppci.ir.Module.

ppci.lang.c.print_ast(ast, file=None)

Display an abstract syntax tree.

ppci.lang.c.parse_text(text, arch='x86_64')

Parse given C sourcecode into an AST


Render a C program as text

For example:

>>> from ppci.lang.c import parse_text, print_ast, render_ast
>>> ast = parse_text('int a;')
>>> print_ast(ast)
Compilation unit with 1 declarations
    Variable [storage=None typ=Basic type int name=a]
        Basic type int
>>> render_ast(ast)
int a;
ppci.lang.c.parse_type(text, context, filename='foo.c')

Parse given C-type AST.

For example:

>>> from ppci.api import get_arch
>>> from ppci.lang.c import parse_type, CContext, COptions
>>> msp430_arch = get_arch('msp430')
>>> coptions = COptions()
>>> context = CContext(coptions, msp430_arch.info)
>>> ast = parse_type('int[2]', context)
>>> context.eval_expr(ast.size)
>>> context.sizeof(ast)
class ppci.lang.c.CBuilder(arch_info, coptions)

C builder that converts C code into ir-code

class ppci.lang.c.CContext(coptions, arch_info)

A context as a substitute for global data

alignment(typ: ppci.lang.c.nodes.types.CType)

Given a type, determine its alignment in bytes

error(message, location)

Trigger an error at the given location


Evaluate an expression right now! (=at compile time)

gen_global_ival(typ, ival)

Create memory image for initial value of global variable

get_field(typ, field_name)

Get the given field.

has_field(typ, field_name)

Check if the given type has the given field.

layout_struct(kind, fields)

Layout the fields in the struct


Determine the bytesize of a memory slab

offsetof(typ, field)

Returns the offset of a field in a struct/union in bytes

pack(typ, value)

Pack a type into proper memory format

sizeof(typ: ppci.lang.c.nodes.types.CType)

Given a type, determine its size in whole bytes

class ppci.lang.c.CLexer(coptions)

Lexer used for the preprocessor

lex(src, source_file)

Read a source and generate a series of tokens


Root parsing function


Scan for a complete character constant


Scan for a complete string


Create tokens from the given text


Generate tokens from characters

class ppci.lang.c.COptions

A collection of settings regarding the C language


Add a path to the list of include paths


Add all the given include paths

classmethod from_args(args)

Create a new options object from parsed arguments.


Given a set of parsed arguments, apply those

class ppci.lang.c.CPreProcessor(coptions)

A pre-processor for C source code

concat(lhs, rhs)

Concatenate two tokens


Handle the ‘##’ token concatenation operator

consume(typ=None, expand=True)

Consume a token of a certain type

copy_tokens(tokens, first_space)

Copy a series of tokens.


Register a macro

define_object_macro(name, text, protected=False)

Define an object like macro.

define_special_macro(name, handler)

Define a spcial macro which has a callback function.

do_if(condition, location)

Handle #if/#ifdef/#ifndef.


Eat up all tokens until the end of the line.

This does not expand macros.

error(msg, hints=None, loc=None)

We hit an error condition.


Evaluate an expression


Expand a single token into possibly more tokens.

expand_macro(macro, macro_token)

Expand a single macro.


Macro expand a sequence of tokens.


Collect expanded arguments for macro

get_define(name: str)

Retrieve the given define!


Process #define directive.


Handle a single preprocessing directive


Process #elif directive.


Process the #else directive.


Process the #endif directive.


Process #error directive.


Process an #if directive.


Handle an #ifdef directive.


Handle an #ifndef directive.


Process the #include directive.


Process the #include_next directive.


Process #line directive.


Process #pragma directive.


Process #undef directive.


Process #warning directive.


Test if the given macro is contained in the current hideset.

include(filename, loc, use_current_dir=False, include_next=False)

Turn the given filename into a series of tokens.

is_defined(name: str) → bool

Check if the given define is defined.

locate_include(filename, loc, use_current_dir: bool, include_next)

Determine which file to use given the include filename.

  • loc (-) – the location where this include is included.
  • use_current_dir (-) – If true, look in the directory of the current file.
static make_token(from_token, typ, value)

Create a new token from another token.


Get next token


Parse an expression in an #if

Idea taken from: https://github.com/shevek/jcpp/blob/master/

Parse filename after #include/#include_next


Define predefined macros

process_file(f, filename=None)

Process the given open file into tokens.


Process a sequence of tokens into an expanded token sequence.

This function returns an tokens that must be looped over.


Push a macro expansion on the stack.


Skip the block excluded by if/ifdef.

Skip tokens until we hit #endif or alike.


Implement __COUNTER__ macro


Invoked when the __DATE__ macro is expanded


Invoked when the __FILE__ macro is expanded


Implement __INCLUDE_LEVEL__ macro


Invoked when the __LINE__ macro is expanded


Implement __TIME__ macro

stringify(hash_token, snippet, loc)

Handle the ‘#’ stringify operator

substitute_arguments(macro, args)

Return macro contents with substituted arguments.

Pay special care to # and ## operators, When an argument is used in # or ##, it is not macro expanded.


Peek one token ahead without taking it.


Create a text from the given tokens

undefine(name: str)

Kill a define!


Undo token consumption.

class ppci.lang.c.CParser(coptions, semantics)

C Parser.

Implemented in a recursive descent way, like the CLANG[1] frontend for llvm, also without the lexer hack[2]. See for the gcc c parser code [3]. Also interesting is the libfim cparser frontend [4].

The clang parser is very versatile, it can handle C, C++, objective C and also do code completion. This one is very simple, it can only parse C.

[1] http://clang.org/ [2] https://en.wikipedia.org/wiki/The_lexer_hack [3] https://raw.githubusercontent.com/gcc-mirror/gcc/master/gcc/c/ c-parser.c

[4] https://github.com/libfirm/cparser/blob/ 0cc43ed4bb4d475728583eadcf9e9726682a838b/src/parser/parser.c


Check if the upcoming token is a typedef identifier


Determine whether we are facing a declaration or not


Advance to the next token


Here the parsing of C is begun …

Parse the given tokens.


Process array initializers.

For example an array maybe initilized with a single value. Or, one can use an designated initializer.


Parse some attributes.

Examples are:



Parse a break


Parse a function call


Parse a case


Parse a series of statements surrounded by ‘{‘ and ‘}’


Parse an expression between parenthesis


Parse a constant expression


Parse a continue statement


Parse the rest after the first declaration spec.

For example we have parsed ‘static int’ and we will now parse the rest. This can be either a function, or a sequence of initializable variables. At least it will probably contain some sort of identifier and an optional pointer stuff.


Parse declaration specifiers.

At the end we know type, storage class and qualifiers.

Gathers storage classes: - typedef - extern - static

One of the following type specifiers: - void, char, int, unsigned, long, … - typedef-ed type - struct, union or enum

Type qualifiers: - const - volatile


Parse normal declarations


Given a declaration specifier, parse the rest.

This involves parsing optionally pointers and qualifiers and next the declaration itself.


Parse the default case


Parse a do-while statement


Parse a statement that does nothing!


Parse an enum definition

parse_enum_fields(ctyp, location)

Parse enum declarations


Parse an expression.

See also: http://en.cppreference.com/w/c/language/operator_precedence


Parse a for statement


Parse function postfix. We have type and name, now parse function arguments

parse_function_declaration(decl_spec, d)

Parse a function declaration with implementation


Parse a gnu attribute like __attribute__((noreturn))


Parse a goto


Parse an if statement


Based on type, determine what we could expect.

This function is only called somewhere within { and }.


Parse a label statement


Parse a primary expression


Parse a return statement


Parse a statement


Parse either a statement or a declaration

Returns: a list of statements


Parse struct or union fields

parse_struct_initializer(struct_typ, initializer)

Match an initializer onto a struct type


Parse a struct or union


Parse an switch statement


Top level start of parsing


Parse the pointer, name and array or function suffixes.

Can be abstract type, and if so, the type may be nameless.

The result of all this action is a type modifier list with the proper type modifications required by the given code.

parse_typedef(decl_spec, d)

Process typedefs


Parse a type specifier used in sizeof(int) for example.

parse_union_initializer(union_typ, initializer)

Match an initializer onto a union type


Parse the C-style array or struct initializer stuff.

Heavily copied from: https://github.com/rui314/8cc/blob/master/parse.c

Argument is the type to initialize.

An initialization can be one of: = 1; = {1, 2, 3}; = {[0] = 3}; // C99 = {.foobar = {23, 3}}; // C99 = {[2..5] = 2}; // C99


Parse a while statement

class ppci.lang.c.CAstPrinter(file=None)

Print AST of a C program

class ppci.lang.c.CSemantics(context)

This class handles the C semantics


Add the given declaration to current scope

apply_type_modifiers(type_modifiers, typ)

Apply the set of type modifiers to the given type

coerce(expr: ppci.lang.generic.nodes.Expression, typ: ppci.lang.c.nodes.types.CType)

Try to fit the given expression into the given type


Called at the end of a function

static error(message, location, hints=None)

Trigger an error at the given location

get_common_type(typ1, typ2, location)

Given two types, determine the common type.

The common type is a type they can both be cast to.


Retrieve a type by type specifiers

not_impl(message, location)

Call this function to mark unimplemented code

on_array_index(base, index, location)

Check array indexing

on_basic_type(type_specifiers, location)

Handle basic type

on_binop(lhs, op, rhs, location)

Check binary operator

on_builtin_offsetof(typ, member_name, location)

Check offsetof builtin function

on_builtin_va_arg(arg_pointer, typ, location)

Check va_arg builtin function

on_builtin_va_copy(dest, src, location)

Check va_copy builtin function

on_builtin_va_start(arg_pointer, location)

Check va_start builtin function

on_call(callee, arguments, location)

Check function call for validity

on_case(value, statement, location)

Handle a case statement

on_cast(to_typ, casted_expr, location)

Check explicit casting

on_char(value, location)

Process a character literal

on_default(statement, location)

Handle a default label

on_do(body, condition, location)

The almost extinct dodo!

on_enum(tag, location)

Handle enum declaration

on_enum_value(ctyp, name, value, location)

Handle a single enum value definition

on_field_def(storage_class, ctyp, name, modifiers, bitsize, location)

Handle a struct/union field declaration

on_field_select(base, field_name, location)

Check field select expression

on_for(initial, condition, post, body, location)

Check for loop construction

on_function_argument(typ, name, modifiers, location)

Process a function argument into the proper class

on_function_declaration(storage_class, typ, name, modifiers, location)

Handle function declaration

on_if(condition, then_statement, no, location)

Check if statement

on_number(value, location)

React on numeric literal

on_return(value, location)

Check return statement

on_sizeof(typ, location)

Handle sizeof contraption

on_string(value, location)

React on string literal

on_struct_or_union(kind, tag, fields, location)

Handle struct or union definition

on_switch_exit(expression, statement, location)

Handle switch statement

on_ternop(lhs, op, mid, rhs, location)

Handle ternary operator ‘a ? b : c’

on_type(typ, modifiers, location)

Called when a type itself is described

static on_type_qualifiers(type_qualifiers, ctyp)

Handle type qualifiers

on_typedef(typ, name, modifiers, location)

Handle typedef declaration

on_typename(name, location)

Handle the case when a typedef is refered

on_unop(op, a, location)

Check unary operator semantics

on_variable_access(name, location)

Handle variable access

on_variable_declaration(storage_class, typ, name, modifiers, location)

Given a declaration, and a declarator, create the proper object

on_variable_initialization(variable, expression)

Handle a variable initialized to some value

on_while(condition, body, location)

Handle the while statement

class ppci.lang.c.CSynthesizer

Take an IR-module and convert it into a C-AST.

This does essentially the opposite of the codegenerator.


Synthesize an ir block into C


Convert ir instruction to its corresponding C counterpart

class ppci.lang.c.CPrinter(f=None)

Render a C program as text


Spit out a declaration


Format an expression as text


Render a single statement as text


Render compilation unit as C

render_type(typ, name=None)

Generate a proper C-string for the given type

class ppci.lang.c.CTokenPrinter

Printer that can turn a stream of token-lines into text


digraph "classes_foo" {
"0" [label="{ArrayType|size\l|}", shape="record"];
"1" [label="{BasicType|CHAR : str\lDOUBLE : str\lFLOAT : str\lINT : str\lINTEGER_TYPES\lLONG : str\lLONGDOUBLE : str\lLONGLONG : str\lSHORT : str\lSIGNED_INTEGER_TYPES : set\lUCHAR : str\lUINT : str\lULONG : str\lULONGLONG : str\lUNSIGNED_INTEGER_TYPES : set\lUSHORT : str\lVOID : str\ltype_id\l|}", shape="record"];
"2" [label="{CType|is_double\lis_float\lis_integer\lis_scalar\lis_signed\lis_struct\lis_union\lis_void\lqualifiers : NoneType\l|}", shape="record"];
"3" [label="{EnumType|complete\lconstants : NoneType\l|}", shape="record"];
"4" [label="{Field|bitsize\lis_bitfield\lname\ltyp\l|}", shape="record"];
"5" [label="{FunctionType|argument_types\larguments\lis_vararg : bool\lreturn_type\l|}", shape="record"];
"6" [label="{IndexableType|element_type\l|}", shape="record"];
"7" [label="{PointerType|\l|}", shape="record"];
"8" [label="{StructOrUnionType|complete\lfields : NoneType\lfields : property\lincomplete\ltag : NoneType\l|get_field()\lget_field_names()\lget_named_fields()\lhas_field()\l}", shape="record"];
"9" [label="{StructType|\l|}", shape="record"];
"10" [label="{UnionType|\l|}", shape="record"];
"0" -> "6" [arrowhead="empty", arrowtail="none"];
"1" -> "2" [arrowhead="empty", arrowtail="none"];
"3" -> "2" [arrowhead="empty", arrowtail="none"];
"5" -> "2" [arrowhead="empty", arrowtail="none"];
"6" -> "2" [arrowhead="empty", arrowtail="none"];
"7" -> "6" [arrowhead="empty", arrowtail="none"];
"8" -> "2" [arrowhead="empty", arrowtail="none"];
"9" -> "8" [arrowhead="empty", arrowtail="none"];
"10" -> "8" [arrowhead="empty", arrowtail="none"];
digraph "classes_foo" {
"0" [label="{ArrayIndex|base\lindex\l|}", shape="record"];
"1" [label="{ArrayInitializer|init_values\l|}", shape="record"];
"2" [label="{BinaryOperator|a\lb\lop\l|}", shape="record"];
"3" [label="{BuiltIn|\l|}", shape="record"];
"4" [label="{BuiltInOffsetOf|member\lquery_typ\l|}", shape="record"];
"5" [label="{BuiltInVaArg|arg_pointer\l|}", shape="record"];
"6" [label="{BuiltInVaCopy|dest\lsrc\l|}", shape="record"];
"7" [label="{BuiltInVaStart|arg_pointer\l|}", shape="record"];
"8" [label="{CExpression|lvalue\ltyp\l|}", shape="record"];
"9" [label="{Cast|expr\lto_typ\l|}", shape="record"];
"10" [label="{CharLiteral|\l|}", shape="record"];
"11" [label="{CompoundLiteral|init\l|}", shape="record"];
"12" [label="{FieldSelect|base\lfield\l|}", shape="record"];
"13" [label="{FunctionCall|args\lcallee\l|}", shape="record"];
"14" [label="{ImplicitCast|\l|}", shape="record"];
"15" [label="{ImplicitInitialValue|\l|}", shape="record"];
"16" [label="{Initializer|\l|}", shape="record"];
"17" [label="{InitializerList|elements\l|}", shape="record"];
"18" [label="{Literal|value\l|}", shape="record"];
"19" [label="{NumericLiteral|\l|}", shape="record"];
"20" [label="{Sizeof|sizeof_typ\l|}", shape="record"];
"21" [label="{StringLiteral|\l|}", shape="record"];
"22" [label="{StructInitializer|field_values : dict\l|}", shape="record"];
"23" [label="{TernaryOperator|a\lb\lc\lop\l|}", shape="record"];
"24" [label="{UnaryOperator|a\lop\l|}", shape="record"];
"25" [label="{UnionInitializer|field : NoneType\lvalue : NoneType\l|}", shape="record"];
"26" [label="{VariableAccess|name\lvariable\l|}", shape="record"];
"0" -> "8" [arrowhead="empty", arrowtail="none"];
"1" -> "16" [arrowhead="empty", arrowtail="none"];
"2" -> "8" [arrowhead="empty", arrowtail="none"];
"3" -> "8" [arrowhead="empty", arrowtail="none"];
"4" -> "3" [arrowhead="empty", arrowtail="none"];
"5" -> "3" [arrowhead="empty", arrowtail="none"];
"6" -> "3" [arrowhead="empty", arrowtail="none"];
"7" -> "3" [arrowhead="empty", arrowtail="none"];
"9" -> "8" [arrowhead="empty", arrowtail="none"];
"10" -> "18" [arrowhead="empty", arrowtail="none"];
"11" -> "8" [arrowhead="empty", arrowtail="none"];
"12" -> "8" [arrowhead="empty", arrowtail="none"];
"13" -> "8" [arrowhead="empty", arrowtail="none"];
"14" -> "9" [arrowhead="empty", arrowtail="none"];
"15" -> "16" [arrowhead="empty", arrowtail="none"];
"16" -> "8" [arrowhead="empty", arrowtail="none"];
"18" -> "8" [arrowhead="empty", arrowtail="none"];
"19" -> "18" [arrowhead="empty", arrowtail="none"];
"20" -> "8" [arrowhead="empty", arrowtail="none"];
"21" -> "18" [arrowhead="empty", arrowtail="none"];
"22" -> "16" [arrowhead="empty", arrowtail="none"];
"23" -> "8" [arrowhead="empty", arrowtail="none"];
"24" -> "8" [arrowhead="empty", arrowtail="none"];
"25" -> "16" [arrowhead="empty", arrowtail="none"];
"26" -> "8" [arrowhead="empty", arrowtail="none"];
digraph "classes_foo" {
"0" [label="{Break|\l|}", shape="record"];
"1" [label="{CStatement|\l|}", shape="record"];
"2" [label="{Case|statement\lvalue\l|}", shape="record"];
"3" [label="{Continue|\l|}", shape="record"];
"4" [label="{DeclarationStatement|declaration\l|}", shape="record"];
"5" [label="{Default|statement\l|}", shape="record"];
"6" [label="{DoWhile|body\lcondition\l|}", shape="record"];
"7" [label="{Empty|\l|}", shape="record"];
"8" [label="{ExpressionStatement|expression\l|}", shape="record"];
"9" [label="{For|body\lcondition\linit\lpost\l|}", shape="record"];
"10" [label="{Goto|label\l|}", shape="record"];
"11" [label="{If|condition\lno\lyes\l|}", shape="record"];
"12" [label="{Label|name\lstatement\l|}", shape="record"];
"13" [label="{Return|value\l|}", shape="record"];
"14" [label="{Switch|expression\lstatement\l|}", shape="record"];
"15" [label="{While|body\lcondition\l|}", shape="record"];
"0" -> "1" [arrowhead="empty", arrowtail="none"];
"2" -> "1" [arrowhead="empty", arrowtail="none"];
"3" -> "1" [arrowhead="empty", arrowtail="none"];
"4" -> "1" [arrowhead="empty", arrowtail="none"];
"5" -> "1" [arrowhead="empty", arrowtail="none"];
"6" -> "1" [arrowhead="empty", arrowtail="none"];
"7" -> "1" [arrowhead="empty", arrowtail="none"];
"8" -> "1" [arrowhead="empty", arrowtail="none"];
"9" -> "1" [arrowhead="empty", arrowtail="none"];
"10" -> "1" [arrowhead="empty", arrowtail="none"];
"11" -> "1" [arrowhead="empty", arrowtail="none"];
"12" -> "1" [arrowhead="empty", arrowtail="none"];
"13" -> "1" [arrowhead="empty", arrowtail="none"];
"14" -> "1" [arrowhead="empty", arrowtail="none"];
"15" -> "1" [arrowhead="empty", arrowtail="none"];
digraph "classes_foo" {
"0" [label="{CDeclaration|is_function\llocation\lname\lstorage_class\ltyp\l|}", shape="record"];
"1" [label="{ConstantDeclaration|value\l|}", shape="record"];
"2" [label="{EnumConstantDeclaration|value\l|}", shape="record"];
"3" [label="{EnumDeclaration|constants\l|}", shape="record"];
"4" [label="{FunctionDeclaration|body : NoneType\l|}", shape="record"];
"5" [label="{ParameterDeclaration|\l|}", shape="record"];
"6" [label="{Typedef|\l|}", shape="record"];
"7" [label="{VariableDeclaration|initial_value\l|}", shape="record"];
"1" -> "0" [arrowhead="empty", arrowtail="none"];
"2" -> "0" [arrowhead="empty", arrowtail="none"];
"3" -> "0" [arrowhead="empty", arrowtail="none"];
"4" -> "0" [arrowhead="empty", arrowtail="none"];
"5" -> "0" [arrowhead="empty", arrowtail="none"];
"6" -> "0" [arrowhead="empty", arrowtail="none"];
"7" -> "0" [arrowhead="empty", arrowtail="none"];


This section contains some links to other compilers. These were used to draw inspiration from. In the spirit of: it is better to steal ideas then invent something bad yourself :).

Other C compilers

A c99 frontend for libfirm: https://github.com/libfirm/cparser


tcc: tiny c compiler

This compiler is tiny and uses a single pass to parse and generate code.



This compiler does parsing and type checking in one go.


CDT is an eclipse c/c++ ide.