C as an intermediate language

Here's a Forth program debugged in KDevelop – a graphical debugger without Forth support:

KDevelop used to debug Forth code

Cool stuff, not? The syntax highlighting for Forth files – that's someone else's work that comes with the standard KDevelop installation. But the rest – being able to run Forth under KDevelop, place breakpoints, and look at program state – all that stuff is something we'll develop below.

I'll show all the required code; we don't have to do very much, because we get a lot for free by using C as an intermediate language.

A high-level intermediate language is not unusual. A lot of compilers target an existing high-level platform instead of generating native code – for instance, by generating JVM bytecode or JavaScript source code. Why? Because of all the things you get for free that way:

  • Portability
  • Optimization
  • Some degree of library interoperability
  • Some degree of tools interoperability (IDEs, debuggers, etc.)

A few languages targeting high-level platforms are rather well-known: Scala and Clojure with compilers targeting the JVM, CoffeeScript and Dart which are compiled to JavaScript. (Then there's Java, which Google famously compiles to JavaScript – though that remains somewhat offbeat.)

Which languages of this kind are the most successful? Without doubt, today the answer is C++ and Objective-C – languages whose first compilers emitted C code.

I think C is an awesome intermediate language for a compiler to emit. It's extremely portable, it compiles in a snap, optimizes nicely, and you get interoperability with loads of stuff.

When I wanted to make a compiler for an interpreted language we developed internally, I actually thought about targeting a VM, not a source language. I planned to emit LLVM IR. It was GD who talked me out of it; and really, why LLVM IR?

After all, LLVM IR is less readable than C, less stable than the C standard – and less portable than C. It will likely always be, almost by definition.

Even if LLVM runs on every hardware platform, LLVM IR will only be supported by the LLVM tools – but not, say, the GNU tools, or Visual Studio. Whereas generating C code gives you great support by LLVM tools – and GNU, and Visual Studio. Debugging a program generated from LLVM IR in Visual Studio will probably always be inferior to debugging auto-generated C code compiled by the Visual Studio compiler.

"C as an intermediate language" is one of those things I wanted to write about for years. What prevented me was, I'd like to walk through an example – including some of the extra work that may be required for better debugging support. But I couldn't think of a blog-scale example ("web-scale" seems to be the new synonym for "loads of data"; I propose "blog-scale" to mean "small enough to fully fit into a blog post".)

Then it dawned on me: Forth! The minimalist language I've fallen out of love with that still has a warm place in my heart.

So, I'll do a Forth-to-C compiler. That'll fit in a blog post – at least a small Forth subset will – and Forth is different enough from C to be interesting. Because my point is, it doesn't have to be C with extensions like C++ or Objective-C. It can be something rather alien to C and you'll still get a lot of mileage out of the C tools supplied by your platform.

Without further ado, let's implement a toy Forth-to-C compiler. We shall:

Enough Forth to not be dangerous

To be dangerous, we'd have to support CREATE/DOES> or COMPILE or POSTPONE or something of the sort. We won't – we'll only support enough Forth to implement Euclid's GCD.

So here's our Forth subset – you can skip this if you know Forth:

  • Forth has a data stack.
  • Integers are pushed onto the stack. When you say 2 3, 2 is pushed and then 3.
  • Arithmetic operators pop operands from the stack and push the result. 6 2 / pops 6 and 2 and pushes 6/2=3. 2 3 = pushes 0 (false), because 2 is not equal to 3.
  • Stack manipulation words, well, manipulate the stack. DUP duplicates the top of the stack: 2 DUP is the same as 2 2. Swap: 2 3 SWAP is the same as 3 2. Tuck: 2 3 TUCK is the same as… errm… 3 2 3. As you can already imagine, code is more readable with less of these words.
  • New words are defined with : MYNAME …code… ; Then if you say MYNAME, you'll execute the code, and return to the point of call when you reach the semicolon. No "function arguments" are declared – rather, code pops arguments from the stack, and pushes results. Say, : SQUARE DUP * ; defines a squaring word; now 3 SQUARE is the same as 3 DUP * – it pops 3 and pushes 9.
  • Loops: BEGIN … cond UNTIL is like do { … } while(!cond), with cond popped by the UNTIL. BEGIN … cond WHILE … REPEAT is like while(1) { … if(!cond) break; … }, with cond popped by the WHILE.
  • Printing: 2 . prints "2 ". CR prints a newline.
  • Forth is case-insensitive.

That's all – enough to implement GCD, and to scare and startle your infix-accustomed friends.

"Compilation strategy"

…A bit too dumb to be called a strategy; anyway, our blog-scale, blog-strength compiler will work as follows:

  • The stack is an array of "data"; data is a typedef for long.
  • Each user-defined word is compiled to a C function getting a data* pointing to the top of stack (TOS), and returning the new TOS pointer.
  • Where possible, built-in words can be used similarly to user-defined words: s=WORD(s).
  • Some words can't work that way: + can't become s=+(s) because that's not valid C. For such words, we do some trivial translation. 2 becomes PUSH(2), + becomes OP2(+). Similarly, control flow words are translated to do/while, if and break.
  • The stack grows downwards and shrinks upwards: if s[0] is the TOS, s[1] is the element below it, etc; s++ shrinks the stack by popping the TOS.

That's all; for instance, the gcd example from here:

: gcd begin dup while tuck mod repeat drop ;

…compiles to the C code below. As you can see, every word is translated in isolation – the compiler has almost no comprehension of "context" or "grammar":

data* gcd(data* s) { //: gcd
  do {               //begin
    s=dup(s);        //dup
    if(!*s++) break; //while
    s=tuck(s);       //tuck
    OP2(%);          //mod
  } while(1);        //repeat
  s=drop(s);         //drop
  return s;          //;

Here's the full Python source of the compiler (forth2c.py) – a bit redundant after all the explanations:

import sys
# "special" words - can't emit s=WORD(s)
special = {
  ':':'data* ',
  ';':'return s; }',
  'begin':'do {',
  'until':'} while(!*s++);',
  'repeat':'} while(1);',
  'while':'if(!*s++) break;',
# binary operators
binops='+ - * / = < > mod'.split()

def forth2c(inf,out):
  n = 0
  for line in inf:
    n += 1
    # emit line info for C tools (debuggers, etc.)
    # - a nice option C gives us
    print >> out,'n#line',n,'"%s"'%infile
    for token in line.lower().strip().split():
      if token in special:
        print >> out,special[token],
          num = int(token)
          print >> out, 'PUSH(%d);'%num,
        except ValueError:
          if token in binops:
            print >> out,'OP2(%s);'%op2c.get(token,token),
            if defining:
              print >> out,token+'(data* s) {',
            else: # call
              print >> out,'s=%s(s);'%token,
      defining = token == ':'

out = open('forth_program.c','w')
print >> out, '#include "forth_runtime.h"'
for infile in sys.argv[1:]:

And here's the "runtime library", if you can call it that (forth_runtime.h). It's the kind of stack-fiddling you'd expect: s++, s--, s[0]=something.

#include <stdio.h>
typedef long data;

#define PUSH(item) (--s, *s = (item))
#define OP2(op) (s[1] = s[1] op s[0], ++s)
#define PRINT() (printf("%ld ", s[0]), ++s)
#define cr(s) (printf("n"), s)
#define drop(s) (s+1)
#define dup(s) (--s, s[0]=s[1], s)
#define tuck(s) (--s, s[0]=s[1], s[1]=s[2], s[2]=s[0], s)

#define MAX_DEPTH 4096 //arbitrary
data stack[MAX_DEPTH];
data* forth_main(data*);
int main() { forth_main(stack+MAX_DEPTH); return 0; }

Note that our Forth dialect has an entry point word – forth_main – that is passed a pointer to an empty stack by C's main. Real Forth doesn't have an entry point – it's more like a scripting language that way; but the forth_main hack will do for our example.

That's all! A Forth dialect in under 60 LOC. By far the shortest compiler I ever wrote, if not the most useful.

A test

Let's test our forth2c using a few example source files. countdown.4th (from here):

    DUP .
    1 -
    DUP 0 =

gcd.4th (a multi-line version – to make single-stepping easier):

: gcd


: forth_main
  5 countdown
  10 6 gcd .
  35 75 gcd .
  12856 3248 gcd .

We can run the program with the shell script:

./forth2c.py countdown.4th gcd.4th main.4th
gcc -g -static -Wall -o forth_program forth_program.c

This should print:

5 4 3 2 1
2 5 8

So countdown manages to count down from 5 to 1, and gcd finds the gcd. Good for them.


Let's try our program with the trusty gdb:

$ gdb forth_program
There is NO WARRANTY!! etc. etc.
(gdb) b countdown # place breakpoint
Breakpoint 1: file countdown.4th, line 3.
(gdb) r # run
Breakpoint 1, countdown (s=0x804e03c) at countdown.4th:3
(gdb) bt # backtrace
#0  countdown (s=0x804e03c) at countdown.4th:3
#1  forth_main (s=0x804e03c) at main.4th:2
#2  main () at forth_runtime.h:14
(gdb) l # list source code
3	    DUP .
4	    1 -
5	    DUP 0 =
7	  DROP
8	;


Seriously, yay. We placed a breakpoint. We got a call stack – forth_main called countdown.  And we've seen the Forth source code of the function we debug. All that in a debugger that has no idea about Forth.

Partly it's due to compiling to high-level primitives, such as functions, that are supported by tools – we'd get that in every language. And partly it's due to #line – something we don't get everywhere.

#line is brilliant – all languages should have it. That's how we tell debuggers where our assembly code is really coming from – not the intermediate C code, but the real source.

Profilers and other tools

It's not just debuggers that understand #line – it's also profilers, program checkers, etc.

Here's KCachegrind showing the profile of our Forth program, obtained using Valgrind as follows:

valgrind --tool=callgrind ./forth_program
kcachegrind `ls -t callgrind* | head -1`

KCachegrind profiling Forth code

Now isn't that spiffy?

C compilers are also aware of #line – which we could try to abuse by pushing error reporting onto the C compiler. Say, if we use an undefined word do_something, we get an error at just the right source code line:

main.4th:3: implicit declaration of function ‘do_something

A very sensible error message – and we didn't have to do anything! Now let's try a BEGIN without a REPEAT – let's delete the REPEAT from countdown.4th:

gcd.4th:1: error: expected ‘while’ before ‘data’

Um, not a very good message. Perhaps this isn't such a good idea after all. If we want quality error reporting, we have to do the error checking at the source language level.

Custom data display: gdb pretty-printers

Things look rather nice. C tools – gdb, Valgrind, KCachegrind – are doing our bidding, aren't they?

Except for the data stack. Instead of the stack elements, gdb shows us the TOS pointer in hexadecimal: countdown (s=0x804e03c), forth_main (s=0x804e03c), which looks a bit lame.

It's not that the local variable s is useless – on the contrary, that's what we use to look at the data stack. This can be done using gdb commands such as p s[0] (prints the TOS), p s[1] (prints the element below TOS), etc. But we'd much rather look at the whole stack at a time, so that we can see how TUCK tucks our numbers into the stack as we single-step our code.

Can it be done?

  • The good news are that it's easy enough with gdb pretty-printers. (To me it became easy after Noam told me about the pretty-printers.)
  • The bad news are that, unlike the case with the universally supported #line, it's impossible to do custom pretty-printing in a uniform way for all tools. There's no "#line for pretty-printing" – quite a pity.
  • But then the good news are that gdb front-ends such as KDevelop or Eclipse support gdb pretty-printers – to an extent. (KDevelop apparently does a better job than Eclipse.) So you don't have to write a GUI plugin or something equally horrible.

Here's a gdb pretty printer for displaying our Forth data stack. It prints all the elements, from bottom to top (as the Forth stack contents is usually spelled). The TOS pointer is the data* you pass for printing – typically, some function's local variable s. The bottom of the stack is known statically – it's the pointer past the end of the global stack[] array. (If we had threads, that array would be thread-local, but anyway, you get the idea.)

So here's gdb_forth.py:

class StackPrettyPrinter(object):
  bottom = None
  bot_expr = 'stack + sizeof(stack)/sizeof(stack[0])'
  def __init__(self,s):
    self.s = s
  def to_string(self):
    if not self.bottom:
      self.bottom = gdb.parse_and_eval(self.bot_expr)
    s = self.s
    i = 0
    words = []
    while s[i].address != self.bottom:
      i += 1
    return ' '.join(reversed(words))

def stack_lookup_func(val):
  if str(val.type) == 'data *':
    return StackPrettyPrinter(val)

print 'loaded Forth extensions'

gdb.pretty_printers is a list of functions which may decide to wrap gdb.Value they're passed in a pretty-printer class object. Typically they decide based on the value's type. gdb.parse_and_eval returns a gdb.Value representing the value of the given C expression. A gdb.Value has a type, an address, etc. If the gdb.Value is a pointer, you can index it as a Python list: val[ind], and if it's a struct, you can use it as a dict: val['member_name'] (we don't have an example of that one here).

If you're interested in gdb pretty printers – a couple of notes:

  • Getting values from other values is much faster than parse_and_eval which just grinds the CPU to a halt; so learning the not-that-Pythonic-while-also-not-that-C-like syntax of gdb.Value access is very worthwhile.
  • You can return "maps" or "arrays" instead of plain strings. Pretty-printers for STL maps and vectors work that way. This can be used to pretty-print high-level data structures such as dynamic objects (if you're lucky and your design matches gdb's view of things – I found a lot of devil in the details.)

Let's test-drive our pretty printer – but first, let's register it in our ~/.gdbinit:

python execfile('/your/path/to/gdb_forth.py')

And now:

$ gdb forth_program
There is NO WARRANTY!!
loaded Forth extensions # aha, that's our printout!
(gdb) b gcd
(gdb) r
Breakpoint 1, gcd (s=10 6) # and that's the stack
(gdb) python for i in range(4): gdb.execute('c')
# continue 4 times
Breakpoint 1, gcd (s=6 4)
Breakpoint 1, gcd (s=4 2)
Breakpoint 1, gcd (s=2 0)
# these were the steps of gcd(10,6)
Breakpoint 1, gcd (s=35 75)
3           dup
# new inputs - gcd(35,75). let's single-step:
(gdb) s # step (execute DUP)
4         while
(gdb) p s # print s
$1 = 35 75 75 # so DUP duplicated the 75.
(gdb) s # step (execute WHILE)
5           tuck
(gdb) p s
$2 = 35 75 # ...and WHILE popped that 75.
(gdb) s # and now we execute the mighty TUCK:
6           mod
(gdb) p s
$3 = 75 35 75 # YES! Tucked the 75 right in!
(gdb) bt # and how's main's data stack looking?
#0  gcd (s=75 35 75) at gcd.4th:6
#1  forth_main (s=75 35) at main.4th:5
# well, it looks shorter - somewhat sensibly.
# (main TOS pointer is unchanged until gcd returns.)

I think it's rather nice. 10 6, 6 4, 4 2, 2 0 – a concise enough walk through Euclid's algorithm in Forth.

KDevelop with the stack display

And, finally, here's how it looks in KDevelop (where the stack displayed in the GUI changes upon every step, as one would expect from a good debugger). The stack is in the variables view on the left.

There is nothing special to be done to make things work in KDevelop – except for the standard procedure of convincing it to debug a user-supplied executable, as you might do with a C program.

Features that don't map naturally to C

Some features of a source language map more naturally to C than others. If we tried to tackle a language different from Forth – or to tackle all of Forth instead of a small subset – some features would pose hard problems.

Some such features can be handled straightforwardly with another intermediate language. For example, dynamic data attributes map to JavaScript much more nicely than they do to C.

But in many cases you don't pick your intermediate language because it's the most suitable one for your source language. If you want to target browsers, then it pretty much has to be JavaScript, even if it's a poor fit for your source language. Similarly, in other situations, it has to be C – or JVM, or .NET, etc.

In fact, many language designers made it their key constraint to play nicely with their platform – the intermediate language. Some advertise the harmonious integration with the platform in the language name: C++, Objective-C, CoffeeScript, TypeScript. They know that many users are more likely to choose their language because of its platform than for any other reason, because they're locked into the platform.

With that said, here are a few features that don't map straightforwardly to C, and possible ways to handle them.

  • Dynamic binding: easy enough. Generate something like call(object,method_id), or call(object,"method_name"), multidispatch(method,obj1,obj2) – whatever you want. Should work nicely.
  • Dynamic code generation – eval, etc.: C doesn't have eval – but it does have fopen("tmp.c"), fwrite, system("gcc -o tmp.so tmp.c …"), dlopen("tmp.so"), and dlsym. This can give you something a lot like eval. You need non-portable code to make it work, but not much of it. Alternatively, if a relatively slow eval with relatively poor debugger support is OK (often it is), you can implement eval using an interpreter, which can reuse the parser of your static compiler. We use both methods in a few places and it works fine.
  • Dynamic data: Code generation is easy – access(object,"attr_name") or whatever. The ugly part is viewing these objects in debuggers. One approach is pretty-printers or similar debugger scripting. Another approach – for "static enough data" – is to generate C struct definitions at runtime, compile them to a shared library with debug info, and load the library, as you'd do to implement eval.
  • Exceptions: I use setjmp/longjmp for that; I think that's what cfront did.
  • Garbage collection: AFAIK it can work fine, funnily enough. There are garbage collectors for C, such as the Boehm collector. Do they work for C programs? Not really – they can mistake a byte pattern that happens to look like a pointer for an actual pointer, causing a leak. But you don't have that problem – because your C program is generated from code that your compiler can analyze and then tell the collector where to look for pointers. So while gc doesn't truly work for C, it can work fine for languages implemented on top of C!
  • Generics, overloading, etc.: most of this is handled by your compiler, the only problem being name mangling. You can mangle names in a way that you find least ugly, or you can mangle them according to the C++ mangling convention, so that debuggers then demangle your names back into collection<item> or some such. (The C++ mangling convention is not portable so you might need to support several.)
  • Multiple return values: we pass pointers to all return values except the first; I think returning a struct might make things look nicer in debuggers. Of course the calling convention will be less efficient compared to a compiler emitting assembly rather than C. But it will still be more efficient than your actual competition, such as a Python tuple.
  • Program reduction (as in, transform (+ (* 2 3) 5) to (+ 6 5), then to 11): ouch. I guess it could make sense to write an interpreter to do that in C, but you wouldn't get that much mileage out of the C optimizer, and no mileage at all from C debuggers, profilers, etc. The basic model of computation has to be close enough to C to gain something from the C toolchain besides the portability of your C code implementing your language. (I'm not saying that you absolutely have to create a memory representation of (+ 6 5) at runtime – just that if you want to create it, then C tools won't understand your program.)

What about using C++ instead of C?

You could, and I did. I don't recommend it. You get exceptions for free instead of fiddling with setjmp/longjmp. Then they don't work when you throw them from one shared library and catch in another (I think RTTI has similar problems with shared libraries). You get templates for free. Then your auto-generated code compiles for ages.

Eli Bendersky writes about switching from C to C++ to implement a language VM. He says it's easier to use C++ features when they match your VM's needs then to reimplement them in C.

Here's how it worked out for me. I once implemented a VM and an interpreter in C++. Then we wrote a compiler for the language. Because the VM was in C++, it was much easier for the compiler to emit C++ code interfacing with the VM than C code. And then with this auto-generated C++ code, we bumped into shared-library-related problems, and build speed problems, etc. – and we have them to this day.

But of course, YMMV. One reason to use C++ is that debuggers get increasingly better at displaying STL collections and base class object pointers (which they know to downcast to the real runtime type and show the derived class members). If your language constructs map to these C++ features, you can get better debug-time data display in a portable way.

Anything you'd like to add?

If you have experience with using C as an intermediate language, I'll gladly add your comments. I'm more experienced with some things than others in this department, and so a lot of the potential issues would likely never occur to me.


C is a great intermediate language, and I'd be thrilled to see more new languages compiling to C. I don't live in either Java or JavaScript these days; surely I'm not alone. A language compiling to C could be fast, portable, have nice tools and library support – and immediately usable to many in the land of C, C++ and Objective-C.


#1 Miroslav Bajtoš (@bajtos) on 09.30.12 at 8:53 am

Hello Yossi, have you heard about Vala? It's compiling C#-like language to C, using GObject from Gtk+ for OOP.


#2 Steve on 09.30.12 at 3:05 pm

I'm also pretty interested in seeing how simple typed (or untyped I suppose) functional languages might be able to leverage C++11's new lambda support as a natural target, as well as deal with C++'s automatic memory management via unique_ptr and shared_ptr instead of relying on garbage collection. It would be interesting to see if a fairly high-level functional language could map to C++11's model and thereby achieve similar performance. I agree that your library-related problems could show up, but maybe the right thing is to just make sure not to rely on C++'s exception mechanism. For example, using std::pair return values might help achieve something similar to Haskell's Either type, which can be used to implement a monadic exception model.

#3 philip andrew on 09.30.12 at 7:26 pm

I asked this question here about how to dynamically reload compiled c/c++ code quickly, its related http://stackoverflow.com/questions/12319329/how-to-dynamically-load-often-re-generated-c-code-quickly/12322672

#4 Yossi Kreinin on 10.01.12 at 1:05 am

@Steve: if you're generating code (as opposed to writing it by hand), then there seems to be relatively little benefit in generating C++ that undergoes rather complicated (and slow) transformations to become something not unlike C inside compared to generating C directly. How is std::pair better than a C struct? It doesn't look better in debuggers and it compiles more slowly. Similarly for lambdas which become pairs of an anonymous function + an anonymous struct. There can be some benefit in generating C++ maps or class hierarchies as I mentioned above – namely debugger support – but I don't see it with every C++ feature (perhaps mistakenly for some of such features which might become better-supported in the future in ways that I don't currently imagine).

#5 Ivan Tikhonov on 10.01.12 at 2:39 am

I am doing exactly the same (Forth to C in Python) and here is my quick summary of things:


#6 Araq on 10.01.12 at 5:35 am

You just described how Nimrod works. Please check it out. ;-)

#7 Yossi Kreinin on 10.01.12 at 7:38 am

@Miroslav, @Araq: cool stuff, heard something about it :)

@philip: looks like they didn't quite answer how to reload code… I'd think dlclose and then dlopen could do the trick, especially if the names were different every time, but I dunno.

@Ivan: you did surprise me :) Is this recreational or do you have concrete plans to use it?

#8 No One on 10.01.12 at 8:16 am

Useful tool: libtcc (from Bellard's tinycc.org) lets you compile directly to memory without any intermediate files /dlopen / dlsym. While it has no optimizer to speak of, it IS comparable to -O0 code from gcc, and it is incredibly fast.

Is there any compiler that implements a #line+column? e.g. it would be nice if your forth example could indicate which parts of the C code correspond to which input part of the line – so you wouldn't have to (unnaturally) insert newlines in the code just to make it a breakpoint target.

#9 Alexey on 10.01.12 at 8:55 am

@Steve Cannot say a thing about C++ lambdas, but I would expect horrible performance from shared_ptr. Reference counting have nonzero overhead and functional language tend to allocate a lot of short lived objects (few GB/s is normal allocation rate for haskell). Generational GC is probably better in this case.

Also C is not good target language for functional languages. Tail call elimination is essential but there is no way to do it in portable C. You have either to use compiler-specific extensions and lose some portability or use trampolies. This is because C doesn't give you any control over stack.

Another case when C is not appropriate choice is when you want to control what machine code is generated for specific language constructs.

#10 Yossi Kreinin on 10.01.12 at 9:02 am

@No One: I think that in any environment, you basically want line-level single-stepping to be line-level, and the fact that your formatting of the code affects the meaning of a "single step" is a feature, not a bug.

#11 Ivan Tikhonov on 10.01.12 at 9:19 am

@Yossi: i hope it's serious, but i think it's 10th my attempt at Forth for my personal use. But they get better each time :)

I like C and mostly write programs in it, but it is quite verbose and some limitations (which can be solved by proper macros) really annoy me.

But i am worrying a bit it may be just an unconscious excuse to procrastinate instead of working toward my goals.

#12 Yossi Kreinin on 10.01.12 at 9:22 am

@Ivan: I have a tendency to counter my wish to procrastinate through meta-programming in some brutal way of, "OK, don't do that, show me (myself, that is) some progress"; basically making myself feel as if there was a deadline and that it has to be done, doesn't matter how. Works to an extent.

#13 Ivan Tikhonov on 10.02.12 at 8:49 am

Thanks, that helps. :-)

#14 Alex on 10.02.12 at 9:26 am

@Alexey: "You have either to use compiler-specific extensions and lose some portability or use trampolies. This is because C doesn't give you any control over stack."

…or you could just have a compiler switch to choose between "optimised" vs. "portable fallback"?

It's a bit of a pain, but actually implementing proper tailcalls in a platform-specific way really isn't that hard, and at least you can still guarantee safety for the platforms you don't care about enough to optimise.

#15 Ivan Tikhonov on 10.02.12 at 10:24 am

@Alex: …or you could just have a compiler switch to choose between "optimised" vs. "portable fallback"?

Tail call is not only about speed and optimization. It's about having recursion without blowing stack.

Implementing tail calls just for the sake of optimization is meaningless in case of Forth, as you gain more from automatic inling than from tail calls.

#16 Alex on 10.02.12 at 2:14 pm

True, but implementing tail calls *slowly* isn't too hard: you can do it fairly easily with some combination of thunks and runtime type checking. So C's lack of built in support for tail calls is really more of an optimisation question, in that you need to get into the non-portable stuff mainly for the sake of making them work *well*.

#17 Ivan Tikhonov on 10.02.12 at 11:42 pm

@Alex "True, but implementing tail calls *slowly* isn't too hard: you can do it fairly easily with some combination of thunks and runtime type checking."

I am not sure what you mean, but won't it not only slow down tail calls, but whole code? Seems like it will involve a lot of indirect calls and prevent inlining.

#18 Alex on 10.03.12 at 10:40 am

Indeed it would, but it also prevents the stack from overflowing, and it's the easiest way to do it in portable, standard-compliant C.

That's what I meant by a compiler switch: one option to be non-portable, relying on asm tweaks or compiler settings, that get the behaviour you actually want ("real" tail calls); and one option that is portable but slows down the whole code, for platforms you haven't written the non-portable version for yet (indirect calls).

All I'm saying is that you shouldn't necessarily feel you have to exclusively choose between ISO C and machine code output: there is still a flexible middle ground for you to take advantage of when your language doesn't match C quite so well.

#19 oren on 10.04.12 at 11:41 pm

The GHC Haskell compiler has a mode in which it outputs C code, and another one where it then compiles the C code using GCC.


Now Haskell is *the* most popular pure functional language today, also it has a default of lazy evaluation, which means many, many thunks are created around from an innocent-looking line of code.

While the docs say this mode is now deprecated in favor of using direct native code generator or LLVM, this does makes Yossi's arguments about using C as an intermediate language much stronger.

#20 Dmitry on 10.06.12 at 1:51 am

Прикольно, я не знал про #line и про то, что все инструменты, основанные на gcc, можно приделать к другому языку через C, спасибо за ликбез.

В среде Racket, кстати, есть аналогичные средства, и вместо сгенерированного текста с #line там няшные макросы, порождающие синтаксические объекты (родные для Racket) с привязками к произвольным локациям в исходном файле. И возможности ВМ позволяют легко реализовать любой язык на свете. Но, действительно, использовать всё это потом можно только в Racket, и о разных там Eclipse и Valgrind остаётся только мечтать.

Вместо "news are", кажется, правильнее "news is".

#21 ann on 10.10.12 at 9:02 pm

thanks this

#22 oliver on 02.19.13 at 7:58 am

Haxe (http://haxe.org/doc/features) is a language that only supports compilation to other existing languages (C++, Javascript, Java…). The concept seems neat, but I'm not sure whether the language itself is actually well-designed.

#23 Leo on 07.17.13 at 5:17 am

I'm finding C to be a wonderful language even if you *do* work in the JavaScript space. We've been building Superconductor, a system for real-time visualization of big data sets, and under-the-hood, compile to OpenCL (a C variant) to use the GPU. Most browsers don't have OpenCL bindings (WebCL), so we also generate JavaScript.

Two performance benefits arise: we found the JavaScript that looks like C to be much faster than normal looking JavaScript, and if you use the Emscripten compiler (C–LLVM–>JS), newer browsers basically run it as if it were C (asm.js).

#24 vs on 07.17.13 at 6:20 am

There exist a language/compiler named 'Harbour', which is able to generate both pseudo-code ("pcode") and ANSI C output. Pseudo-code output also uses C as an intermediate language, thus, pcode and ANSI C objects can be freely mixed, and both can be transparently compiled to binary using the tool 'hbmk2'. There is also an option to generate portable pcode binaries (.hrb).

#25 John Cowan on 10.17.14 at 8:43 pm

The Scheme language has several compilers that convert to higher-level languages. In particular, Gambit, Chicken, Bigloo, and Larceny are independent implementations that compile to C. On the JVM and CLR, it's more usual to compile to bytecode rather than Java or C# source: Kawa and Bigloo compile to JVM bytecode, and Larceny and IronScheme to CLR bytecode. Most other Schemes are bytecode compilers with or without JITs, native x86 compilers, or tree-walking interpreters. Links to these implementations can be found in the fairly complete list of Schemes. In addition, Common Lisp implementations include Embeddable Common Lisp and its descendent ManKai CL, which compile to C, as well as Armed Bear CL, which compiles to JVM bytecode.

Chicken is an especially interesting case, because it supports both proper tail calls and call with current continuation without extra expense using Cheney on the MTA, a technique whereby each Scheme procedure is compiled to a C procedure that calls its successor rather than returning, winding up the stack until it becomes large enough, at which point all live local data is flushed to the heap and the stack is reset with longjmp().

#26 Lewis Andrew Campbell on 11.23.14 at 12:29 am

I've been working on a stack based VM this weekend, and this blog post was really helpful. I would never have thought of just keeping a pointer to the stack and decrementing the address, instead of keeping an index to the top element. I did have many mysterious segfaults copying this technique though, until I realised you had to initialise the stack as pointing just past the last element.

#27 Lucio on 01.03.15 at 3:33 am

>>"C is a great intermediate language"
I've reached the same conclusion after coding a compile-to-c mode for a lang: LiteScript.
Initially designed to compile-to-js, I was pleased to see how good fit is C for an intermediate language.
Note: I did also used setjmp/longjmp for exceptions and the Boehm GC.
Check it at: https://github.com/luciotato/LiteScript

#28 alpha.tau on 08.07.15 at 12:49 am

All this talk about C being a "great/useful/suitable" intermediate language begs a simple question – is there
a library out there somewhere to simplify the development of a C backend/code-generator, instead of
having to "reinvent the wheel" each and every time?

#29 Sean B. Palmer on 09.20.15 at 6:46 pm

I'm not sure how this happened, but it did:


#30 Yossi Kreinin on 09.20.15 at 7:25 pm

I'm flattered, I guess…

I really should go over the blog and fix the shit done by the various WP upgrades over the years where the text gets fucked up and no longer compiles. Oh, WP, WP…

#31 none on 12.31.16 at 12:01 am

1) Boehm GC actually works pretty well in practice– see the literature about it.

2) Purescript (purescript.org) compiles to C++ in a useful way, basically using std::shared_ptr as a poor implementer's GC. Its usual back end is javascript though.

#32 Williamtom on 04.02.19 at 12:58 am

Qcharge inc. is launching Qfino Quick charge, wireless and solar powerbank
Click here to get a chance to win free and by sharing link you can earn pints,


#33 Evgenswottesovenna on 04.03.19 at 4:15 am

Хотелось купить готовый сайт со скидкой в интернете-магазине сайтов Юлии Беззубовой!
Выбрал макет и хотел запустить сайт сразу. Как оказалось сайт "Бистро" не продается со скидкой. Сначала расстроился, но поискал в интернете и не нашел аналогов.
Через 1 неделю вернулся в студию сайтов Юлии и попросил счет на безналичный рассчет. После оформления заказа через 5 дней этот макет стал моим сайтом. Сейчас в Google рекламе в Краснодаре уже месяц рекламируют. Отдача от рекламы просто превзошла все ожидания. На праздники была полная загруженность.
Спасибо Юлии за хорошую работу.

#34 Hasphalm on 05.01.19 at 1:00 am

Надеюсь подборка понравилась, следующая подборочка, будет про кошечек)

#35 Dox on 05.06.19 at 3:16 pm

Срочно продам заготовки RW15 по 38руб. (900шт.) брелки MIFARE 1K (Бесконтактный RFID брелок с чипом Mifare S50) по 9руб. (7000шт.) 8 917 715 99 60. Отправлю почтой или СДЭКом за свой счет,заготовки оплатите после проверки при получении.

#36 Candida Sprowl on 05.14.19 at 5:09 pm

Like the site – extremely easy to navigate and lots to think about!

#37 istripper crack on 05.15.19 at 5:58 pm

I have interest in this, xexe.

#38 DarrellUneda on 05.17.19 at 10:10 pm

it's an excellent site!So much helpful info and handy ideas, bless you =)

#39 vn hax pubg on 06.16.19 at 10:35 pm

Thanks for this post. I definitely agree with what you are saying.

#40 roblox executor on 06.17.19 at 5:52 am

Awesome, this is what I was searching for in bing

#41 proxo key generator on 06.19.19 at 9:11 am

Great, yahoo took me stright here. thanks btw for this. Cheers!

#42 proxo key generator on 06.19.19 at 11:36 am

I have interest in this, danke.

#43 vn hax on 06.20.19 at 6:08 pm

I like this site because so much useful stuff on here : D.

#44 vn hax pubg mobile on 06.20.19 at 8:17 pm

I conceive you have mentioned some very interesting details , appreciate it for the post.

#45 nonsense diamond download on 06.21.19 at 7:21 am

Intresting, will come back here again.

#46 badoo superpowers free on 06.23.19 at 4:49 pm

Yeah bookmaking this wasn’t a risky decision outstanding post! .

#47 badoo superpowers free on 06.23.19 at 6:47 pm

Hey, yahoo lead me here, keep up great work.

#48 gx tool apk download on 06.24.19 at 2:53 pm

stays on topic and states valid points. Thank you.

#49 gx tool apk on 06.24.19 at 4:52 pm

Great article to see, glad that bing led me here, Keep Up cool job

#50 free online Q & A on 06.25.19 at 4:42 am

Your website has proven useful to me.

#51 Explain Like I’m Five on 06.25.19 at 6:48 am

Intresting, will come back here once in a while.

#52 fortnite mods on 06.25.19 at 7:34 pm

Enjoyed reading through this, very good stuff, thankyou .

#53 geometry dash 2.11 download pc on 06.25.19 at 9:29 pm

Thanks for this post. I definitely agree with what you are saying.

#54 skisploit on 06.26.19 at 6:13 am

very cool post, i actually love this web site, carry on it

#55 krunker aimbot on 06.26.19 at 8:08 am

very cool post, i actually love this web site, carry on it

#56 MikeLug on 06.26.19 at 4:39 pm

Лучшие проститутки Питера, шлюхи и путаны Санкт-Петербурга
Проститутки Питера это самое яркое воплощение сексуальности и женской красоты
Ни для кого не секрет, что проститутки Питера это самое яркое воплощение женской красоты, сексуальности и раскрепощенности. Лучшие проститутки Питера способны свести с ума даже самых закоренелых семьянинов и верных мужей и подарить им те часы радости и сексуального наслаждения, которых они никогда не смогут получить от своих привычных партнеров, жен, подруг. Проститутки Питера позволят Вам воплотить в реальность все свои самые смелые и необычные фантазии, а сделают они это очень умело и профессионально. Питера проститутки в большинстве своем сами обожают секс и с радостью ставят всевозможные сексуальные эксперименты и пожалуй ни одна девушка не сможет сравниться в мастерстве с проверенными проститутками Питера. Ну разве Вы не мечтаете оказаться в объятиях обворожительной и нежной красотки? Рядом с которой Вы будете чувствовать себя настоящим мужчиной.

#57 ispoofer activation key on 06.27.19 at 5:41 am

Hello, here from yahoo, i enjoyng this, will come back soon.

#58 ispoofer on 06.27.19 at 7:27 am

I consider something really special in this site.

#59 synapse x cracked on 06.27.19 at 8:29 pm

Enjoyed reading through this, very good stuff, thankyou .

#60 synapse x serial key free on 06.27.19 at 10:19 pm

Some truly wonderful posts on this web site , appreciate it for contribution.

#61 strucid aimbot on 06.28.19 at 7:02 am

Good Morning, bing lead me here, keep up great work.

#62 strucid hacks on 06.28.19 at 9:01 am

I simply must tell you that you have an excellent and unique site that I kinda enjoyed reading.

#63 advanced systemcare 11.5 pro key on 06.28.19 at 1:13 pm

Thanks for this site. I definitely agree with what you are saying.

#64 cryptotab hack script free download 2019 on 06.29.19 at 8:21 am

Respect to website author , some wonderful entropy.

#65 cryptotab script hack free on 06.29.19 at 2:42 pm

Some truly wow article on this web site , appreciate it for contribution.

#66 choices stories you play free on 07.01.19 at 8:50 am

I enjoying, will read more. Cheers!

#67 hackear zg survival on 07.01.19 at 10:13 am

I love reading through and I believe this website got some genuinely utilitarian stuff on it! .

#68 codes for mining simulator 2019 on 07.01.19 at 7:37 pm

Thanks for this article. I definitely agree with what you are saying.

#69 free cheats for rust on 07.02.19 at 7:28 am

Great, bing took me stright here. thanks btw for post. Cheers!

#70 escape from tarkov cheats and hacks on 07.02.19 at 8:58 am

I conceive you have mentioned some very interesting details , appreciate it for the post.

#71 nonsense diamond on 07.02.19 at 1:02 pm

Enjoyed reading through this, very good stuff, thankyou .

#72 vnhax download on 07.03.19 at 7:09 am

google brought me here. Cheers!

#73 vnhax download on 07.03.19 at 8:29 am

Thank You for this.

#74 cyberhackid on 07.03.19 at 7:06 pm

Hi, glad that i saw on this in bing. Thanks!

#75 roblox prison life hack on 07.04.19 at 7:05 am

I like this website its a master peace ! Glad I found this on google .

#76 seo man on 07.04.19 at 1:21 pm

Parasite backlink SEO works well :)

#77 phantom forces aimbot on 07.04.19 at 6:51 pm

This is awesome!

#78 open dego on 07.05.19 at 7:05 am

This is great!

#79 Олег on 07.05.19 at 5:41 pm


#80 tom clancy's the division hacks on 07.05.19 at 7:19 pm

Thanks for this post. I definitely agree with what you are saying.

#81 erdas foundation 2015 on 07.05.19 at 8:49 pm

I conceive you have mentioned some very interesting details , appreciate it for the post.

#82 synapse x on 07.06.19 at 6:45 am

Cheers, great stuff, Me enjoying.

#83 Hoyt Brassard on 07.06.19 at 10:19 am

The next phase of the puzzle is to decipher the order of the pyramid. This is your 3rd secret lead… 517232125

#84 gx tool uc hack apk on 07.06.19 at 10:57 am

very interesting post, i actually love this web site, carry on it

#85 Радик on 07.06.19 at 2:30 pm

Ку ку

#86 rekordbox torrent on 07.06.19 at 9:48 pm

This is interesting!

#87 rekordbox torrent on 07.07.19 at 12:47 am

stays on topic and states valid points. Thank you.

#88 Макс on 07.07.19 at 4:41 am


#89 black ops 4 license key on 07.07.19 at 8:16 am

I really enjoy examining on this blog , it has got fine goodies .

#90 call of duty black ops 4 keygen on 07.07.19 at 10:12 am

I simply must tell you that you have an excellent and unique site that I must say enjoyed reading.

#91 spyhunter serial on 07.08.19 at 8:19 am

I was looking at some of your articles on this site and I believe this internet site is really instructive! Keep on posting .

#92 spyhunter key on 07.08.19 at 10:30 am

Ha, here from bing, this is what i was looking for.

#93 Валерий on 07.09.19 at 1:44 am

Нужна помощь

#94 roblox fps unlocker download on 07.09.19 at 9:55 am

This is amazing!

#95 roblox fps unlocker on 07.09.19 at 12:13 pm

Your website has proven useful to me.

#96 click on 07.15.19 at 3:01 am

I simply want to say I am just newbie to blogs and honestly liked your web blog. Probably I’m want to bookmark your website . You really come with terrific articles. Thanks for sharing your web-site.

#97 legalporno free on 07.16.19 at 12:11 am

great advice you give

#98 DavidSuics on 07.17.19 at 6:14 am

fuck sex gay dick

#99 Office movers on 07.18.19 at 1:41 pm

Have you ever thought about writing an ebook or guest authoring on other sites? I have a blog based on the same subjects you discuss and would really like to have you share some stories/information. I know my visitors would appreciate your work. If you are even remotely interested, feel free to shoot me an e mail.

#100 Bobs discount furniture assembly on 07.18.19 at 4:49 pm

I really like your writing style, fantastic info, thank you for putting up :D. "Much unhappiness has come into the world because of bewilderment and things left unsaid." by Feodor Mikhailovich Dostoyevsky.

#101 Tractor Workshop Manuals on 07.18.19 at 5:03 pm

Kinds of Engines vacation packages ‘re affordable, of benefit nevertheless, you pick up every single single single ability required by specific bargain. Search Engine Optimization

#102 cubicle installation on 07.18.19 at 5:55 pm

I've been browsing on-line greater than three hours as of late, yet I by no means found any interesting article like yours. It is beautiful value sufficient for me. In my view, if all web owners and bloggers made just right content material as you probably did, the internet can be a lot more helpful than ever before. "I finally realized that being grateful to my body was key to giving more love to myself." by Oprah Winfrey.

#103 paris_hill on 07.19.19 at 1:56 am

just what I needed to read

#104 Rolando Vonseggern on 07.19.19 at 2:25 am

Skyking, Skyking, this drop is your next bit of data. Please message the agency at your earliest convenience. No further information until next transmission. This is broadcast #5190. Do not delete.

#105 Rolland Gembarowski on 07.19.19 at 2:45 am

Skyking, this note is your next bit of information. Please message the agency at your earliest convenience. No further information until next transmission. This is broadcast #6685. Do not delete.

#106 buydrugonline on 07.19.19 at 2:57 am

This blog is amazing! Thank you.

#107 Furniture assembly service on 07.19.19 at 6:16 am

Excellent read, I just passed this onto a colleague who was doing a little research on that. And he just bought me lunch as I found it for him smile Therefore let me rephrase that: Thanks for lunch!

#108 Tanitim on 07.19.19 at 4:07 pm

I am extremely impressed with your writing skills and also with the layout on your blog. Is this a paid theme or did you modify it yourself? Anyway keep up the excellent quality writing, it is rare to see a great blog like this one today..

#109 Home gym assembly on 07.20.19 at 9:00 am

Thank you for the good writeup. It in fact was a amusement account it. Look advanced to far added agreeable from you! However, how can we communicate?

#110 Alexandria movers on 07.20.19 at 10:51 am

fantastic issues altogether, you simply won a new reader. What could you suggest in regards to your publish that you simply made a few days in the past? Any certain?

#111 Movers on 07.20.19 at 1:38 pm

Howdy are using WordPress for your blog platform? I'm new to the blog world but I'm trying to get started and create my own. Do you need any coding expertise to make your own blog? Any help would be really appreciated!

#112 Pool table repair on 07.20.19 at 2:40 pm

I’ve read several good stuff here. Certainly worth bookmarking for revisiting. I surprise how much effort you put to make such a magnificent informative site.

#113 binary winning strategy on 07.20.19 at 11:39 pm

I want to show some thanks to this writer for rescuing me from this type of instance. Because of surfing around throughout the internet and obtaining principles which were not powerful, I figured my entire life was over. Living without the approaches to the issues you have solved by means of the article is a critical case, as well as the kind which may have in a negative way affected my entire career if I had not noticed your blog post. Your skills and kindness in playing with every part was invaluable. I don't know what I would've done if I had not come across such a subject like this. I'm able to now look forward to my future. Thank you very much for the reliable and results-oriented help. I will not be reluctant to suggest your web sites to any individual who ought to have direction about this problem.

#114 WW88 on 07.21.19 at 5:50 am

Admiring the hard work you put into your site and detailed information you offer. It's great to come across a blog every once in a while that isn't the same outdated rehashed information. Excellent read! I've bookmarked your site and I'm adding your RSS feeds to my Google account.

#115 งานแต่งงาน on 07.21.19 at 6:43 am

Just wanna input on few general things, The website design and style is perfect, the content is real excellent. "Taxation WITH representation ain't so hot either." by Gerald Barzan.

#116 [prodigy hack] on 07.21.19 at 2:41 pm

I dugg some of you post as I thought they were very beneficial invaluable

#117 first aid e-learning on 07.21.19 at 3:05 pm

Heya i am for the first time here. I found this board and I find It really useful & it helped me out much. I hope to give something back and aid others like you helped me.

#118 prodigy hacks on 07.21.19 at 4:24 pm

Hey, google lead me here, keep up good work.

#119 Delta installation on 07.22.19 at 5:11 am

Excellent goods from you, man. I have understand your stuff previous to and you are just extremely great. I actually like what you've acquired here, certainly like what you are stating and the way in which you say it. You make it entertaining and you still take care of to keep it smart. I cant wait to read far more from you. This is actually a tremendous website.

#120 Саша on 07.22.19 at 5:39 am


#121 Washington DC furniture removal service on 07.22.19 at 6:30 am

Howdy just wanted to give you a quick heads up and let you know a few of the images aren't loading correctly. I'm not sure why but I think its a linking issue. I've tried it in two different browsers and both show the same results.

#122 evogame. net/wifi on 07.23.19 at 12:33 pm

I enjoying, will read more. Thanks!

#123 acid swapper on 07.23.19 at 3:00 pm

Hi, here from google, me enjoyng this, will come back soon.

#124 date c9ougar on 07.23.19 at 11:31 pm

I am 43 years old and a mother this helped me!

#125 lean gains on 07.23.19 at 11:36 pm

I do love the way you have presented this particular challenge and it really does offer me personally some fodder for consideration. However, coming from everything that I have experienced, I just simply trust when the opinions stack on that folks keep on point and don't start upon a soap box involving the news of the day. Yet, thank you for this superb point and while I do not concur with the idea in totality, I regard the point of view.

#126 nike epic react on 07.24.19 at 12:53 am

You made some decent factors there. I looked on the internet for the problem and found most individuals will go together with with your website.

#127 monster hunter world free key on 07.24.19 at 12:57 pm

Intresting, will come back here again.

#128 forza horizon 2 key generator on 07.24.19 at 3:17 pm

I conceive you have mentioned some very interesting details , appreciate it for the post.

#129 W88 ดีไหม W88 โกง on 07.24.19 at 9:44 pm

Perfectly pent subject material , thanks for information .

#130 online giving on 07.25.19 at 6:27 am

I want to show appreciation to this writer just for rescuing me from this type of difficulty. Because of exploring throughout the internet and meeting tricks which are not powerful, I thought my entire life was gone. Being alive without the strategies to the problems you've solved by way of your main posting is a crucial case, and the ones that could have in a wrong way affected my entire career if I had not encountered your web site. Your main capability and kindness in playing with all things was vital. I am not sure what I would've done if I had not come upon such a subject like this. I am able to at this moment look forward to my future. Thanks for your time so much for the professional and sensible guide. I won't be reluctant to recommend the blog to any individual who needs to have assistance about this issue.

#131 ezfrags on 07.25.19 at 2:42 pm

This does interest me

#132 ezfrags on 07.25.19 at 5:34 pm

Great, bing took me stright here. thanks btw for info. Cheers!

#133 W88 on 07.25.19 at 7:00 pm

Hi, i think that i saw you visited my website so i came to “return the favor”.I'm attempting to find things to improve my web site!I suppose its ok to use a few of your ideas!!

#134 air jordans on 07.26.19 at 1:59 am

Youre so cool! I dont suppose Ive learn anything like this before. So good to seek out any individual with some unique thoughts on this subject. realy thanks for beginning this up. this web site is something that is wanted on the internet, someone with a bit originality. helpful job for bringing one thing new to the web!

#135 StevenneM on 07.26.19 at 7:17 am

Enjoy Your Coffee Your Way with A makita battery powered coffee machine

When you are far from your home, finding an excellent cup of coffee can be tough. Sure, there are gasoline station, rest stops and takeaway food locations that sell coffee, however there is nothing to inform you how great it's going to taste.
The coffee may be too strong, too weak or a brand you don't like. A lot of times there is only 1 or 2 size cups available.
The small cup may not hold as much coffee as you want, however the large cup might be more than you can drink before it gets cold.
With modern technology coffee makers are now portable. Whether driving the children for an activity, shopping, camping or a trucker who loves coffee, you can brew your first cup of coffee while driving.
Simply plug a 12-volt coffee maker in the cigarette lighter socket and brew a pot.
Some 12-Volt coffee makers come with mounting brackets for your vehicle.
Avid coffee drinkers know your very first cup of the day is the best. It helps wake you up and gets you going.
Usually, finding a restaurant with decent food is easy, unless you are in an out of the way place. However, finding a great cup of coffee, made the way you like it, can be a problem.
Having a portable coffee maker, you can plug into any 12-volt power source is simply amazing.
Having a thermos travel mug will keep the freshly brewed coffee hot. There are even 12-volt heated travel mugs, that plug right into the cigarette lighter socket, to keep your coffee hot.
There is nothing that tastes better than freshly brewed coffee made your way. It can complete a meal, complement a desert, or be enjoyed by itself.
Because of the 12-Volt technology of a portable coffee maker, you can make coffee the way you like it. You do not have to put up with bad tasting coffee.
When traveling you can enjoy coffee at the right temperature and made just the way you like it. A battery-operated coffee maker can keep you in coffee made the way you like it.
On days I am taking the children to activity’s or just having a day out with the children, I love having a battery-powered coffee maker with me. It saves having to find a place with good coffee, and wait for service.
I save a lot of money
I find this invaluable if I have a lot of driving to do.
RoadPro makes a 12 Volt smart car pot.
Just plug it into any 12-volt lighter/power socket, and you have hot water to mix up hot chocolate, instant soups, noodles and more. It has an automatic shut-off when the liquid pitcher is empty, or input voltage is too high, making it safe to use anywhere.

Look into their 12-Volt Car Espresso Coffee maker. Thanks to an a 12V Car Espresso Coffee Machine, you can enjoy a fresh espresso while driving.
With 12-Volt coffee makers, you can enjoy your coffee made how you like it, no matter where you are at.

#136 visit this site right here on 07.26.19 at 7:22 am

Excellent web site. Lots of useful information here. I am sending it to some buddies ans also sharing in delicious. And obviously, thank you on your sweat!

#137 ezfrags on 07.26.19 at 3:48 pm

I conceive this web site holds some real superb information for everyone : D.

#138 WW88 on 07.26.19 at 6:35 pm

I dugg some of you post as I cerebrated they were invaluable handy

#139 skisploit on 07.26.19 at 6:39 pm

I like this site, some useful stuff on here : D.

#140 nike air max on 07.28.19 at 4:26 am

Youre so cool! I dont suppose Ive read anything like this before. So good to seek out any person with some original ideas on this subject. realy thanks for beginning this up. this web site is something that's wanted on the internet, somebody with slightly originality. useful job for bringing one thing new to the internet!

#141 yesmovies on 12.24.19 at 10:06 am

Throughout the years, the price of instrumentals decreased which includes its positives and negatives.

#142 123movies on 12.24.19 at 10:07 am

"I am actually glad to glance at this website posts which carries lots of helpful data,
thanks for providing these data.


#143 solarmovies on 12.24.19 at 10:07 am

It’s in fact very difficult in this busy life to listen news on TV, thus I only use the web for that purpose,and take the latest news.

#144 fmovies on 12.24.19 at 10:08 am

After looking at a handful of the blog articles on your web site, I seriously like your way of writing a blog. I book-marked it to my bookmark webpage list and will be checking back soon.

#145 123.hp.com/oj4650 on 01.04.20 at 3:08 pm

The driver is one of the essential requirements for a Printer. This facilitates the connection between the system and the HP OfficeJet 4650 printer. Only after this, you can enjoy printing multiple documents of your choice. There are multiple ways you can download the driver. Here is one method that will assist you with printing using HP OfficeJet 4650 printer. Navigate to the 123.hp.com/oj4650, which will take you to the page that has download overlay. Once you click on this, the HP easy start app will download. Follow the instructions on the screen to complete the installation.

#146 123.hp.com/setup 3830 on 01.08.20 at 12:59 pm

Do you need easy and simple instructions to make the 123.hp.com/setup 3830? then here are the instruction. Firstly, remove the printer from the package and place it in a safe place. Then power up the printer using the HDMI power cables. Load the paper insert the ink cartridge. Connect the wireless network to the printer. Then proceed to the driver installation steps. For further tips and tricks regarding the 123.hp.com/setup 3830 get in touch with our customer support team

#147 cara menggugurkan kandungan on 01.18.20 at 5:59 pm

after reading this article post to completion, this is very high quality and very useful content.