Skip to content
master
Switch branches/tags
Code

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
src
 
 
 
 
 
 
 
 
 
 
 
 

Abstract

with-c-syntax is a fun package which introduces the C language syntax into Common Lisp. (Yes, this package is not for practical coding, I think.)

At this stage, this package has almost all features of ISO C 90 freestanding implementation. (The lacking part is the full implementation of the C Preprocessor.)

News

2021-5-24

  • C Numeric Literals are added. (Inspired by @akanouras. See PR #7.) Hexadecimal floating number syntax may be a only practical feature of this package. (Try #{ 0x1.fffp+1; }#)

2019-4-25

  • I added some special handlings around ++, *, etc. The Duff’s Device example becomes prettier.
  • I added a new example, C in Lisp in C in Lisp. (unholy mixture..)

Examples

Hello, World

CL-USER> (with-c-syntax:with-c-syntax ()
    format \( t \, "Hello World!" \) \;
  )

Hello World!
NIL

For suppressing Lisp’s syntax, you need many backslash escapes.

#{ and }# reader macro escapes them and wrap its contents into with-c-syntax. You can use it to write simply:

;; enables #{ }# reader macros.
CL-USER> (named-readtables:in-readtable with-c-syntax:with-c-syntax-readtable)
...

CL-USER> #{ format (t, "Hello World!"); }#

Hello World!
NIL

This example shows you can call a Lisp function (cl:format) with C syntax.

Summing from 1 to 100.

(named-readtables:in-readtable with-c-syntax:with-c-syntax-readtable)

#{
  int i, sum = 0;

  for (i = 0; i <= 100; ++i)
    sum += i;
  return sum;
}#
;; => 5050

Using C syntax inside a Lisp function.

(named-readtables:in-readtable with-c-syntax:with-c-syntax-readtable)

(defun array-transpose (arr)
  (destructuring-bind (i-max j-max) (array-dimensions arr)
    #{
      int i,j;
      for (i = 0; i < i-max; i++) {
          for (j = i + 1; j < j-max; j++) {
	        rotatef(arr[i][j], arr[j][i]);
          }
      }
    }#)
  arr)

(array-transpose (make-array '(3 3)
 		:initial-contents '((0 1 2) (3 4 5) (6 7 8))))
; => #2A((0 3 6) (1 4 7) (2 5 8))

Defining a function with C syntax.

(named-readtables:in-readtable with-c-syntax:with-c-syntax-readtable)

#{
int sum-of-list (list) {
  int list-length = length(list);
  int i, ret = 0;

  for (i = 0; i < list-length; ++i) {
     ret += nth(i, list);
  }

  return ret;
}
}#

(sum-of-list '(1 2 3 4 5 6 7 8 9 10)) ; => 55

Duff’s Device

(named-readtables:in-readtable with-c-syntax:with-c-syntax-readtable)

(defun wcs-duff-device (to-seq from-seq cnt)
    #{
    int *to = &to-seq;
    int *from = &from-seq;

    int n = (cnt + 7) / 8;
    n = floor(n);           /* Lisp's CL:/ produces rational */
    switch (cnt % 8) {
    case 0 :    do {    *to++ = *from++;
    case 7 :            *to++ = *from++;
    case 6 :            *to++ = *from++;
    case 5 :            *to++ = *from++;
    case 4 :            *to++ = *from++;
    case 3 :            *to++ = *from++;
    case 2 :            *to++ = *from++;
    case 1 :            *to++ = *from++;
      } while (--n > 0);
    }
    }#
  to-seq)

(defparameter *array-1*
  (make-array 20 :initial-element 1))

;; C syntax can also be used for defining a variable.
#{
int *array-2* [] = {2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
}#

(wcs-duff-device *array-1* *array-2* 10)
(print *array-1*) ;; => #(2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1)

This example shows some C operators (++, --, unary * and &) behave as you expected as possible.

(This feature is based on @phoe’s suggestion. See Issue #2 .)

C in Lisp in C in Lisp

Sometimes you want to use the Lisp syntax even in with-c-syntax. If you feel so, you can use ` as an escape. Here is an example:

(named-readtables:in-readtable with-c-syntax:with-c-syntax-readtable)

#{
void 99-bottles-of-beer (filename) {
  void * output-path = merge-pathnames (filename, user-homedir-pathname());
  `(with-open-file (*standard-output* output-path :direction :output
				      :if-exists :supersede :if-does-not-exist :create)
     #{
     int b;
     for (b = 99; b >= 0; b--) {
         switch (b) {
         case 0 :
           write-line("No more bottles of beer on the wall, no more bottles of beer.");
           write-line("Go to the store and buy some more, 99 bottles of beer on the wall.");
           break;
         case 1 :
           write-line("1 bottle of beer on the wall, 1 bottle of beer.");
           write-line("Take one down and pass it around, no more bottles of beer on the wall.");
           break;
         default :
           format(t, "~D bottles of beer on the wall, ~D bottles of beer.~%", b, b);      
           format(t, "Take one down and pass it around, ~D ~A of beer on the wall.~%"
                     , b - 1
                     , ((b - 1) > 1)? "bottles" : "bottle");
           break;
         }
     }
     }#);
  return;
  }
}#

(99-bottles-of-beer "99_bottles_of_beer.txt")

(probe-file "~/99_bottles_of_beer.txt") ; => T

This example creates “99_bottles_of_beer.txt” file into your home directory. I used ` for using with-open-file in Lisp syntax.

(You can use any Lisp operators including with-open-file in with-c-syntax style. However it looks very weird; An example exists in my test code.)

How to load

Loading by quicklisp

This library is quicklisp-ready. http://quickdocs.org/badge/with-c-syntax.svg

(ql:quickload "with-c-syntax")

or, Loading manually

Libraries depending on

cl-yacc
As a parser for C syntax
  • alexandria
named-readtables
For exporting ‘#{’ reader syntax.
cl-ppcre
For parsing numeric constants.
trivial-gray-streams
For implementing translation phase 1 and 2 correctly.

by libc

  • osicat
float-features
For math.h, dealing NaN and Infinities.
floating-point-contractions
For math.h, to implement some functions.

by test codes

1am
As a testing framework.
trivial-cltl2
For using compiler-let to test NDEBUG.
floating-point
For comparing mathmatical function results.

Load with ASDF

(asdf:load-asd "with-c-syntax.asd")
(asdf:load-system :with-c-syntax)

Running tests

(asdf:load-asd "with-c-syntax-test.asd")
(asdf:test-system :with-c-syntax)

API

Please see these docstrings or comments:

Further Information

What this macro does is only expanding a list of symbols to a Lisp form.

If you are still interested, please see: https://github.com/y2q-actionman/with-c-syntax/wiki

Vacietis is a similer project. It is a “C to Common Lisp” compiler, based on reader macros.

License

Copyright (c) 2014,2019,2021 YOKOTA Yuki <y2q.actionman@gmail.com>

This program is free software. It comes without any warranty, to the extent permitted by applicable law. You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See the COPYING file for more details.