Let's use a scripting language for a comfortable C ++ life 2 Automatically generate C ++ source

In a previous post, I wrote Let's code with good visibility using std :: map type.

** For embedded environments above a certain level **

If you have more than a certain amount of embedded environment (eg board such as Raspberry Pi or Zynq), you can use g ++ and there should be no problem using STL. And you can write programs using STL containers. I think that STL should be actively used for making a version that works correctly when developing on a PC (I am worried about the implementation of C ++ of some commercial compilers, and STL using that compiler I think the situation is different from the old days when I was worried about the implementation of. At that time, I heard that I was asked to rewrite the code written using STL to non-STL code.) .. The external specifications of STL are clear, and it is easy for multiple members to share a common understanding. As much as I enjoyed using STL, I avoid the effort to fully clarify the specifications and test the algorithms of other parts.

If the final implementation is a PC, you could leave it as STL, or you might choose to leave it as STL in some embedded environments. In this article, for those who still can't use the STL for their final implementation, I suggest using the STL when developing code that works correctly on the PC version by showing that the C ++ source can be automatically generated. It is something to do.

** Script that facilitates migration to an environment where std :: map type cannot be used **

The following Python script reads the mapping data of std :: map <std :: string, int> in the withMap.cpp file and generates a sequence of if () else if () statements without using STL. is.

intoElseif.py


# -*- coding: utf-8 -*-
def parseMap(name):
    u"""
    std::map<std::string, int>Read atmomicNumbers.
Read the map key and value and assign them to the Python dictionary.
    """
    d = {}
    for line in open(name, "rt"):
        oline = line.strip().replace(",", " ")
        if len(oline) > 1 and oline[-1] == ",":
            oline = oline[:-1]
        f = oline.split()
        if len(f) == 4 and f[0] == "{":
            d[int(f[2])] = f[1]
    return d

if __name__ == "__main__":
    u"""
C based on the read dictionary/C++Generate a language if else if statement.
    """
    d = parseMap(name="withMap.cpp")
    keys = d.keys()
    keys.sort()
    k = keys[0]
    print """if(strcmp(instr, %s) == 0){
    r = %s;
}""" % (d[k], k),
    for i in range(1, len(keys)):
        k = keys[i]
        print """else if(strcmp(instr, %s) == 0){
    r = %s;
}""" % (d[k], k),

C ++ file containing std :: map type data of input data

withMap.cpp


#include <iostream>
#include <string>
#include <map>

/**Map type container that associates atomic numbers with element symbols
*Initialization is carried out at the same time as the declaration.
*(Only up to Ne in the second cycle is described.)
*/
std::map<std::string, int> atmomicNumbers = {
	{ "H", 1 },
	{ "He", 2 },
	{ "Li", 3 },
	{ "Be", 4 },
	{ "B", 5 },
	{ "C", 6 },
	{ "N", 7 },
	{ "O", 8 },
	{ "F", 9 },
	{ "Ne", 10 }
};

int main(int argc, char* argv[]){
	std::string symbol = "Be";
	
	std::cout << symbol << " " << atmomicNumbers[symbol] << std::endl;
}

Execution result

generated.cpp


if(strcmp(instr, "H") == 0){
    r = 1;
} else if(strcmp(instr, "He") == 0){
    r = 2;
} else if(strcmp(instr, "Li") == 0){
    r = 3;
} else if(strcmp(instr, "Be") == 0){
    r = 4;
} else if(strcmp(instr, "B") == 0){
    r = 5;
} else if(strcmp(instr, "C") == 0){
    r = 6;
} else if(strcmp(instr, "N") == 0){
    r = 7;
} else if(strcmp(instr, "O") == 0){
    r = 8;
} else if(strcmp(instr, "F") == 0){
    r = 9;
} else if(strcmp(instr, "Ne") == 0){
   r = 10;
}

In this way, it is easy to automatically generate a part of a program from a part of regular data. Therefore, we insist on ensuring the health of the program using a clear data format. If you write a program using std :: map, the effect of increasing data will be { "Ne", 10 } All you have to do is add the following lines, eliminating the need to change the code elsewhere.

I think that it is first to secure a mechanism that can guarantee that it works correctly, and then to secure the performance (processing speed, program size) on the implementation.

** Supplement: **

In the above example, without using std :: map

python


char* [] atomicSymbols = {
    "H", "He",
    "Li", "Be", "B", "c", "N", "O", "F", "Ne"
}

It is also possible to process using the array. However, here we are using the std :: map <std :: string, int> type to suggest using a standard library for the logic that associates keys with values.

** Note: **

Generating parts of a program using a scripting language has long been used by some. When writing a lot of similar contents with only the data replaced, a part of the program was automatically generated based on the data. The data is updated frequently, so it may not be possible to write it by hand once. Such an approach can be used for any language. For example, Ratfor, a FORTRAN extension language, used a preprocessor to hide the shortcomings of the FORTRAN language specification. I think that improving the visibility of the processing being done is to ensure the soundness of the program at an early stage.

Postscript: "Programming Style" Chapter 9 Notation "9.5 Program to write a program" has a name and It is designed to generate an error message based on a header file that contains comments. In that book, a perl script automatically converts it. In this way, the scripting language can be used to accelerate development in the C / C ++ language.

python


enum {
    Eperm,  /* Permission denied */
    Eio,    /* I/O error */
    Efile,  /* File does not exist */
    Emem,   /* Memory limit reached */
    Espace, /* Out of file space */
    Egreg   /* It's all Greg's fault */
};

There is an example of generating the following declaration from.

python


char *errs[] = {
   "Permission denied", /* Eperm */
   "I/O error", /* Eio */
   "File does not exist", /* Efile */
   "Memory limit reached", /* Emem */
   "Out of file space", /* Espace */
   "It's all Greg's fault", /* Egreg */ 
 };

Recommended Posts

Let's use a scripting language for a comfortable C ++ life 2 Automatically generate C ++ source
Use a scripting language for a comfortable C ++ life
Let's use a scripting language for a comfortable C ++ life C ++ implementation after verification with python
Use a scripting language for a comfortable C ++ life 4-Use your own C ++ library from a scripting language-
Use a scripting language for a comfortable C ++ life 3-Leave graphing to matplotlib-
Let's use a scripting language for a comfortable C ++ life 6-How about developing a program as a library for Python?
Use a scripting language for a comfortable C ++ life-OpenCV-Port Python to C ++-
Use a scripting language for a comfortable C ++ life 5 --Use the Spyder integrated environment to check numerical data-
Automatically generate a polarity dictionary used for sentiment analysis
A note for embedding the scripting language in a bash script
Note 2 for embedding the scripting language in a bash script
Scripting Language C ——How a text file without a shebang is executed