Generate C language from S-expressions in Python

Introduction

Notes

――Please think of it as a kind of play. -It is not the story of Gauche's Are. ――The author is not very familiar with C language. Please point out any strange points.

Recently I've been playing with making Lisp in Python.

-Making minimal Lisp with Python (parsing) -Make a minimal Lisp with Python (evaluation + α) -Making minimal Lisp with Python (Jabashi)

This was fun with this, but I wasn't motivated because it wasn't practical, apart from using it and not using it, and I was wondering what to play next. At that time, I remembered reading an article that gauche seems to come with an S-expression → C language transpiler somewhere, and it seemed interesting, so I completely diverted the reader part of my own Lisp. I implemented it in Python. The original one is called CiSE (C in S-Expression), but the one implemented this time is ** a completely different thing **. By the way, it has a rather Common Lisp flavor.

Published under the name CLOP, so if you are interested, please. By the way, it's a name I don't really like, so I might change it if I think of it. CiSE can be cool.

How it works

The flow of generating C language from S-expressions is as follows.

  1. Convert from S-expression to list of character strings
  2. If the beginning of the list is * a predefined function *, call the rest as arguments
  3. If not, treat it as a * C function *

A * predefined function * is, for example:

def aref(array, subscript):
    return f"{array}[{subscript}]"

For example, (aref hoge fuga) is converted to["aref", "hoge", "fuga"](1), and then" hoge [fuga] " is generated (2). is. At this time, if the first element of the list is not looked up, it is processed as a function of c. For example, (printf" hello ") produces " printf (\ "hello \") " (3).

Also, + hoge + is converted to HOGE, and hoge-hoge is converted to hoge_hoge.

I used the expression ** function ** as defined in advance, but the point is that it is like a macro. The following macros are defined in advance in CLOP.

* + - / 1+ 1- < > and aref ash break cast cond continue
decf declare defconstant defenum defstruct defsyntax
defun defunion defvar eq for if incf include let logand
logior logxor mod not or progn return setf when while

Most of the names come from Common Lisp, C, so you can almost imagine what they do.

If there is no oversight, you should be able to handle almost all C language functions.

Illustration

Hello, world!

hello.clop


(include stdio)

(defun int:main (void)
  (printf "Hello, world!\n")
  (return 0))

I think I haven't seen it. The type is declared with the specifiers separated by colons, such as ʻunsigned: int: hoge`. You can convert it to C language with the following command.

$ clop translate hello.clop --out hello.c

hello.c


#include <stdio.h>

int main (void)
{
  printf("Hello, world!\n");
  return 0;
}

macro

You can use macros for the time being. However, CLOP is nothing more than a ** list-> string converter ** after all, so there is no list operation function. Therefore, you cannot use powerful macros like Common Lisp, but you can write more flexibly than macro functions in C language. For example.

python


(defsyntax null (ptr)
  (eq ,ptr +null+))

This is expanded as follows.

hoge == NULL // (null hoge)

It is unpleasant to have backticks even though there are no quotes, but if you add backticks, the value will be inserted from the argument given at the time of macro expansion. This is the same as the CPP macro, so here is a slightly more complicated example. CLOP allows you to use Common Lisp-like optional arguments, keyword arguments, and variadic arguments.

with-open-file.clop


(include stdio)

(defsyntax null (ptr)
  (eq ,ptr +null+))

(defsyntax with-open-file ((stream filespec &optional (mode "w")) &body body)
  (let ((FILE*:,stream (fopen ,filespec ,mode)))
    (if (null ,stream)
      (perror "Failed to open file")
      (progn
        ,@body
        (fclose ,stream)))))

If you do , @ hoge, the contents of the argument will be expanded as it is. (One parenthesis can be taken)

You can write the macro definition in a single source code, but you can also pull it from another file with require. At this time, the header file that is ʻincludeis also pulled at the same time if it is not already included. In addition, except for macro definition and include, it is skipped. Here is an example ofrequire the previous with-open-file.clopwithmain.clop`.

main.clop


(include stdio)
(require with-open-file)

(defun int:main (void)
  (with-open-file (fd "hello.txt")
    (fprintf fd "Hello, world!\n"))
  (return 0))
$ clop translate main.clop --out main.c

main.c


#include <stdio.h>

int main (void)
{
  ({
    FILE* fd = fopen("hello.txt", "w");
    fd == NULL? (perror("Failed to open file")) : (({
      fprintf(fd, "Hello, world!\n");
      fclose(fd);
    }));
  });
  return 0;
}

It's a creepy code, but it works fine. CLOP makes heavy use of compound sentence expressions (such as ({hoge; fuge; ...})), which can make readability terrible in some cases.

Digression

1. Benefits

Let's think about the advantages.

--Improved readability (depending on the person) --The description will be shorter (maybe) --You can use macros with a little flexibility

Except for the third one, it's subtle.

2. Difficulties

I felt that the syntax of C language was complicated. I don't think when writing raw C, but when generating from an S-expression, I was quite worried about where to put parentheses and where to put a semicolon. Given that, I think the expressive power of S-expressions is amazing.

Summary

Implemented Oreore CiSE in Python. I think there is a universal desire to write non-S-expressions in S-expressions (for example, Hy). What about C language? I would like to touch the CiSE of the original gauche, but it is a pity that there is not much information. (Maybe you just can't find it. Please let me know if you have good documentation)

** Addendum ** There was such a thing. https://github.com/burtonsamograd/sxc

Recommended Posts

Generate C language from S-expressions in Python
Call c language from python (python.h)
Generate a class from a string in Python
Next Python in C
C API in Python 3
How to generate permutations in Python and C ++
Extend python in C ++ (Boost.NumPy)
Machine language embedding in C language
Generate rounded thumbnails in Python
Try to make a Python module in C language
OCR from PDF in Python
Binary search in Python / C ++
Generate U distribution in Python
Generate QR code in Python
Generate 8 * 8 (64) cubes in Blender Python
Generate Word Cloud from case law data in python3
Get macro constants from C (++) header file (.h) in Python
Call C from Python with DragonFFI
Multi-instance module test in C language
[Python] Generate QR code in memory
Get data from Quandl in Python
100 Language Processing Knock Chapter 1 in Python
Realize interface class in C language
Generate Jupyter notebook ".ipynb" in Python
Call popcount from Ruby / Python / C #
Introduction to Protobuf-c (C language ⇔ Python)
Solve ABC036 A ~ C in Python
Tips for calling Python from C
Execute Python code from C # GUI
How to wrap C in Python
Run Python scripts synchronously from C #
Python to switch from another language
Solve ABC037 A ~ C in Python
Segfault with 16 characters in C language
Write C unit tests in Python
Call C / C ++ from Python on Mac
Extract strings from files in Python
Call your own C language shared library from Python using ctypes
Generate a first class collection in Python
Linked list (list_head / queue) in C language
Generate AWS-S3 signed (time-limited) URLs in Python
Closure 4 language comparison (Python, JavaScript, Java, C ++)
Algorithm in Python (ABC 146 C Binary Search
Revived from "no internet access" in Python
Prevent double boot from cron in Python
Implement FIR filters in Python and C
Automatically generate Python Docstring Comment in Emacs
Write O_SYNC file in C and Python
Module to generate word N-gram in Python
Download images from URL list in Python
Get battery level from SwitchBot in Python
Socket communication by C language and Python
Use C ++ functions from python with pybind11
Convert from Markdown to HTML in Python
Get Precipitation Probability from XML in Python
Run Python in C ++ on Visual Studio 2017
Get metric history from MLflow in Python
C language to see and remember Part 2 Call C language from Python (argument) string
[C language] I want to generate random numbers in the specified range
C language to see and remember Part 1 Call C language from Python (hello world)
C language to see and remember Part 4 Call C language from Python (argument) double