Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
PicoC: a very small C interpreter for scripting (code.google.com)
76 points by rw- on Sept 3, 2010 | hide | past | favorite | 44 comments


Language interpreters are great for experimenting with new or buggy pieces of code - just experiment at the prompt and copy what works into a file for posterity. I've started looking through the parsing code for PicoC, and its all nice and readable. But I'm surprised this was used in an actual system, embedded or not. C is an absolutely miserable language whose saving graces are executable size and speed. It lacks reasonable features to use for scripting, like code-as-data in Bash or the dynamism of Python and Ruby. There are even embedded scripting languages like LUA. What does C offer as a scripting language, except perhaps familiarity?


As you suggested, it offers the possibility to switch from interpreted to compiled code at no extra effort.


I used Ch[1] in a commercial product and I would highly dis-recommend C as a scripting language. Something has to be said for high-level semantics, dynamism and syntax designed for interactive work. I find Lisp, Lua and Groovy to be joy to work with, but C is not an ideal extension/embedded/scripting language. Use something easier.

http://en.wikipedia.org/wiki/Ch_interpreter


The links for these should read (code.google.com)


Yep, time to add google.com to the "long domain" list . (See http://github.com/nex3/arc/blob/arc3.1/news.arc#L1556)


See also: http://bellard.org/tcc/ a compiler, but small and #!tcc can be put at the top of .c files to make them scripts.

Also see: http://root.cern.ch/drupal/content/cint — an interpretor, but large.


TCC has two even more cool things:

1) a library that lets you compile C code within a process, relocate it and execute it. This is rather faster than shelling out to run gcc to create a shared object and open it using dlopen.

2) an awesome 2004 demonstration where TCC was used as a boot loader. Take the Linux kernel source (slightly modified to remove some of the gccisms), add TCCBOOT and reboot the machine: as part of the boot process TCC recompiles the kernel and the continue to execute the freshly compiled kernel -- all in 15 seconds: http://bellard.org/tcc/tccboot.html


I really love Fabrice, but "TCC" will, forever, remain Turbo C, not Tiny C.

DOS weenie pride!


Ctrl+F9 ftw.


How would you like to have a REPL for kernel development, like on the Lisp Machines? (Yes, that's a rhetorical question!)

Take TCC with your point 1 above. Mix it with the ideas from Schemix ( http://abstractnonsense.com/schemix/ ). Now you can iteratively development a kernel driver!

I hacked on Schemix a while back, updating it to 2.6 module system (unfortunately lost the source code before it got uploaded). It's a seemingly great idea but what good is scheme code if you have to rewrite in a different language for the final version?


An interesting thing about tcc is how fast it is compared to gcc. If you can use it, that might be a great advantage in development times.


That's precisely why I sometimes use it. And that running code through another compiler can sometimes highlight issues that went previously unnoticed.


One thing that was sad was to see how ugly the forking situation got: http://www.landley.net/code/tinycc/

When I was using tcc a lot I used the tinycc fork as it had fixed bugs I was encountering. It's a shame that things didn't work out amicably.


How refreshing to see something that only has 'readline' as a dependency and otherwise just requires a working C compiler and 'make'.


Yeah. Why reuse something when you can write it yourself!


Because:

- each dependecy makes it harder to build your project

- and makes it more brittle (libraries goes obsolete, changes versions, occasionaly have non-backward-compatibile changes, on different systems different versions of libraries are available, etc)

- most of the time you use only small fraction of each library, it is also common (at least in static typing world) that libraries enforces data structures on you, so sometimes it's easier to reinvent wheel, than to integrate your app with some library

- when you need to add some feature to library you often have to go throught hoops (inherit some class, make some wrappers and use it instead of what you'd use normally) - it is much easier to keep things simple, when you have controll over interfaces and can just change what you want, also architecture is simpler without proxies, wrappers and delegates

- static binaries on linux don't work after a few years

- dynamic linked binaries works as long as somebody worries about dependency problems - and this means you

- you can keep all dependencies in VCS together with your project, but often it's not legal (LGPL)

- not really important for most apps - dependencies bloats your app

Dependencies in programming are like moving parts in enginering - there should be as few of them as possible.


I was wondering if you really meant that, given that this is intended to be useful in embedded applications. To try to get a feel for the sort of programming you do and the sort of opinions you hold, I checked your profile - Bang - there's the answer right there:

  > I'm not trolling:
  > I actually think that.
Is it really the case that you don't see the point in writing a minimal, small, clean, self-contained system that has no external dependences and is directly applicable and useful for embedded systems.


I don't find it refreshing to see people writing the same code over and over and over and over again. Does it have a point? Yes. Does it refresh me? No.

(Libraries and dependencies don't necessarily mean "dynamic relinking at runtime". It can mean "link that standard code from ../lets-not-write-a-hashtable-again/hashtable.o".)


Just curious: Is it trolling, if I write out a strong opinion, that I don't necessarily believe, but that sounds reasonable to me, on a topic I'm trying to figure out what to believe, and then, when my sentiments get refuted, I say to myself, "Okay, now there's a reasonable way to think."


No, because you're interested in honest communication. But it would be more honest to phrase the strong opinion as "I don't necessarily believe X, but it sounds reasonable to me. Is there anything wrong with that reasoning?"


Sure, but still. It's rare to see a program that does not require at least another 10 fold its own size in super structure. And the fact that it is targeted to embedded use means that in its destined environment there is none of that stuff available anyway.


I wonder how it compares to other small systems like Lua, or, say Antirez' Jim interpreter, in terms of speed and features.


Hey David, what I think it's cool about picoC is that you can use it in places where you need to script at "hardware" level, like in robotics, embedded systems, and alike.

Otherwise it is probably better to use Lua for instance, since I bet it is much faster (I just read part of the PicoC implementation and it is a pretty straightforward interpreter, very cool to read but hardly the faster) and safer.


Lua can and is used in robotics, embedded system and alike. Take a look at: * pbLua, for Lego Mindstorm (http://www.hempeldesigngroup.com/lego/pblua/) * eLua for small MCU (http://www.eluaproject.net/)


Presumably, it wouldn't be that hard to create some Lua functions to interface with memory addresses, I would think.


Yes but it's a pain to write complex code accessing memory when you need high level functions, can't simply cast pointers to C structures and alike.


Very cool, there is even an interactive prompt. I wonder how hard is to make this interpreter "safe".


define "safe". :)


Running every kind of script will never corrupt the application memory :)


[deleted]


Well, if it's interpreted, the interpreter could sandbox the C code it's running, rather than passing it through directly to its own memory space.


That would kind of defy the whole premise of this thing wouldn't it? The biggest and most sought after "feature" of C is it's speed and direct memory access (and simplicity, I guess).

If you take that away, what's left?


Depends on the application, but I could see some mixture of: 1) familiarity; 2) simplicity; and 3) minimal memory usage. Browsing the source code briefly, it really does look like it's an interpreter, with C structs representing Variables, Expressions, and so on.


Of course it is possible in an interpreter.

You simply need to verify each access before allowing it, much like Valgrind does.

Of course it's quite costly do to so, and since C gives the programmer a lot of freedom I guess it's hard to optimize the tests, i.e. to know which accesses are safe without explicitly keeping track.


Are you sure? Even Valgrind does not detect everything. E.g. when you mess up variables within your stack.


That's quite different. Sandboxing in an interpreter is actually fairly easy.


Ok, you are right.


Personally I would use Forth for this. PicoC looks interesting but if I were to weigh my options (i.e. PicoC vs Forth in his example app UAV-onboard system, I would definitely go Forth).


Care to explain your reasoning behind this?

As I understand, the main appeal of using C as a scripting language is the fact that you use the same language in compiled and interpreted part of your application.

Drawbacks of using C interpreter for scripting could include large footprint and external dependencies, but as far as I can understand, they are not the case here.

So what is your reasoning for Forth?


In the case of embedded programming, Forth is often made for the job. C is great for embedded programming too, and you can always mix the two languages. C isn't made for scripting, and hacks like PicoC don't appeal to me since it will always remain a hack.

While not exactly a scripting language per se, Forth does have amazing interactive capabilities. It's extremely light-weight and it's easy to implement a new Forth on a new hardware architecture. Footprint issues aside, development time in Forth is usually shorter, and the ability to connect directly to a device's Forth "shell" and try out Forth words (functions), create new words, play around with hardware in real-time is invaluable.

Forth code is less readable if you don't know Forth, and occasionally Forth programmers write ugly code, but that is definitely the case for embedded C programmers too.


Would this be allowed in an iPhone application, since it's all C?


AFAIK no programs are allowed which interpret code.


Actually, Apple allows interpreted code under certain circumstances. Link provides more details. I'm not sure how helpful it would be in this case, though. My understanding is that the main motivation for having scripted languages as a small part of an app, as this rule allows, is for game engines which have high-performance graphics stuff in C, and some of the application logic in a language like Lua. The use of a scripting language can reduce development time, but if you were using C, you might as well compile it.

http://arstechnica.com/apple/news/2010/06/devs-cautiously-op...


But in theory you could use it to script C in debug mode, then hard compile the script before you send it to Apple.


So no postscript viewer ever? And no browsers? That's a sad state.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: