2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-15 13:02:11 +00:00
Files
build/src/engine/yyacc.cpp
2021-02-20 21:35:16 -06:00

220 lines
6.7 KiB
C++

/* Copyright 2002, 2020 Rene Rivera.
** Distributed under the Boost Software License, Version 1.0.
** (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt)
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cctype>
#include <set>
#include <cstring>
/*
# yyacc - yacc wrapper
#
# Allows tokens to be written as `literal` and then automatically
# substituted with #defined tokens.
#
# Usage:
# yyacc file.y filetab.h file.yy
#
# inputs:
# file.yy yacc grammar with ` literals
#
# outputs:
# file.y yacc grammar
# filetab.h array of string <-> token mappings
#
# 3-13-93
# Documented and p moved in sed command (for some reason,
# s/x/y/p doesn't work).
# 10-12-93
# Take basename as second argument.
# 12-31-96
# reversed order of args to be compatible with GenFile rule
# 11-20-2002
# Reimplemented as a C program for portability. (Rene Rivera)
# 05-xx-2020
# Reimplement yet again, in C++. (Rene Rivera)
*/
static const std::string usage[] = {
"yyacc <grammar output.y> <token table output.h> <grammar source.yy>"
};
void print_usage()
{
for (auto u: usage)
{
std::printf("%s\n", u.c_str());
}
}
std::string tokenize_string(std::string s)
{
std::string result = s;
if (s == ":") result = "_colon";
else if (s == "!") result = "_bang";
else if (s == "!=") result = "_bang_equals";
else if (s == "&&") result = "_amperamper";
else if (s == "&") result = "_amper";
else if (s == "+") result = "_plus";
else if (s == "+=") result = "_plus_equals";
else if (s == "||") result = "_barbar";
else if (s == "|") result = "_bar";
else if (s == ";") result = "_semic";
else if (s == "-") result = "_minus";
else if (s == "<") result = "_langle";
else if (s == "<=") result = "_langle_equals";
else if (s == ">") result = "_rangle";
else if (s == ">=") result = "_rangle_equals";
else if (s == ".") result = "_period";
else if (s == "?") result = "_question";
else if (s == "?=") result = "_question_equals";
else if (s == "=") result = "_equals";
else if (s == ",") result = "_comma";
else if (s == "[") result = "_lbracket";
else if (s == "]") result = "_rbracket";
else if (s == "{") result = "_lbrace";
else if (s == "}") result = "_rbrace";
else if (s == "(") result = "_lparen";
else if (s == ")") result = "_rparen";
std::transform(
result.begin(), result.end(), result.begin(),
[](unsigned char c){ return std::toupper(c); });
return result+"_t";
}
struct literal
{
std::string string;
std::string token;
bool operator<(const literal & x) const
{
return this->string < x.string;
}
};
int main(int argc, char ** argv)
{
int result = 0;
if (argc != 4)
{
print_usage();
result = 1;
}
else
{
FILE * token_output_f = 0;
FILE * grammar_output_f = 0;
FILE * grammar_source_f = 0;
grammar_source_f = fopen(argv[3],"r");
if (grammar_source_f == 0) { result = 1; }
if (result == 0)
{
std::set<literal> literals;
char l[2048];
while (1)
{
if (fgets(l,2048,grammar_source_f) != 0)
{
char * c = l;
while (1)
{
char * c1 = std::strchr(c,'`');
if (c1 != 0)
{
char * c2 = std::strchr(c1+1,'`');
if (c2 != 0)
{
auto l = std::string(c1+1,c2-c1-1);
literals.insert({ l, tokenize_string(l) });
c = c2+1;
}
else
break;
}
else
break;
}
}
else
{
break;
}
}
token_output_f = std::fopen(argv[2],"w");
if (token_output_f != 0)
{
for (const literal & l: literals)
{
std::fprintf(token_output_f," { \"%s\", %s },\n",l.string.c_str(), l.token.c_str());
}
std::fclose(token_output_f);
}
else
result = 1;
if (result == 0)
{
grammar_output_f = std::fopen(argv[1],"w");
if (grammar_output_f != 0)
{
for (const literal & l: literals)
{
fprintf(grammar_output_f,"%%token %s\n",l.token.c_str());
}
rewind(grammar_source_f);
while (1)
{
if (fgets(l,2048,grammar_source_f) != 0)
{
char * c = l;
while (1)
{
char * c1 = strchr(c,'`');
if (c1 != 0)
{
char * c2 = strchr(c1+1,'`');
if (c2 != 0)
{
auto replacement = literals.find({std::string(c1+1,c2-c1-1), ""});
*c1 = 0;
std::fprintf(grammar_output_f,"%s%s",c,replacement->token.c_str());
c = c2+1;
}
else
{
std::fprintf(grammar_output_f,"%s",c);
break;
}
}
else
{
std::fprintf(grammar_output_f,"%s",c);
break;
}
}
}
else
{
break;
}
}
std::fclose(grammar_output_f);
}
else
result = 1;
}
}
if (result != 0)
{
perror("yyacc");
}
}
return result;
}