This commit is contained in:
Wolfgang Thaller 2019-08-28 19:44:49 +02:00
parent a0c3b2e9a7
commit 738410da8c
4 changed files with 340 additions and 72 deletions

View file

@ -1,7 +1,8 @@
cmake_minimum_required(VERSION 3.13)
project(MultiversalHeaders)
set(CXX_STANDARD_REQUIRED 17)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED 17)
set(CMAKE_PROGRAM_PATH ${CMAKE_PROGRAM_PATH} "/usr/local/opt/bison/bin")
find_package(BISON 3.0.2)

View file

@ -19,13 +19,14 @@ static std::string strip(const char *p, const char *q)
%option noyywrap
%x preamble
%x executor_only
%%
using hp = yy::HeaderParser;
using token = hp::token;
atBOL = false;
^"#if !defined(_"[A-Z_]+_H_")"$ BEGIN(preamble);
^"#if !defined(_"[A-Za-z0-9_]+_H_")"$ BEGIN(preamble);
<preamble>^"namespace Executor" BEGIN(INITIAL);
<preamble>.|\n ;
@ -92,7 +93,11 @@ static std::string strip(const char *p, const char *q)
[[:alpha:]_][[:alnum:]_]* return hp::make_IDENTIFIER(yytext);
^" "*#.* ;
^" "*#.*(\\\n.*)* return hp::make_EXECUTOR_ONLY(yytext);
^"BEGIN_EXECUTOR_ONLY"\n BEGIN(executor_only);
<executor_only>^"END_EXECUTOR_ONLY"\n BEGIN(INITIAL); atBOL = true;
<executor_only>.*\n return hp::make_EXECUTOR_ONLY(std::string(yytext, yytext + yyleng - 1));
"/*"[^*]*("*"+[^*/]*)*"*"+"/" {
if(atBOL)

View file

@ -15,6 +15,7 @@
%token<std::string> CHARLIT;
%token<std::string> COMMENT;
%token<std::string> RIGHTCOMMENT;
%token<std::string> EXECUTOR_ONLY;
%token LEFTBRACE "{";
%token RIGHTBRACE "}";
@ -71,15 +72,13 @@
%token FOURCC "FOURCC";
%type <YAML::Node> declaration enum struct typedef lowmem trap function size_assertion enum_value
%type <std::vector<YAML::Node>> enum_values enum_values1
%type <std::string> comments rcomment
%type <std::vector<YAML::Node>> struct_members
%type <YAML::Node> struct_member
%type <std::string> expression
%left EXECUTOR_ONLY;
%right COMMENT;
%code requires {
#include "yaml-cpp/yaml.h"
#include <unordered_map>
#include <sstream>
}
%code provides {
yy::HeaderParser::symbol_type yylex();
@ -87,7 +86,34 @@
%code {
#include <stack>
YAML::Emitter yamlout;
std::vector<YAML::Node> things;
std::unordered_map<std::string, int> names;
int gAnonymousIndex = 0;
std::ostringstream executorOnly;
void declare(YAML::Node node)
{
things.push_back(std::move(node));
if(node.begin()->second["name"])
names[node.begin()->second["name"].as<std::string>()] = things.size() - 1;
}
void renameThing(const std::string& name, const std::string& newName)
{
auto p = names.find(name);
if(p != names.end())
{
int idx = p->second;
names.erase(p);
names[newName] = idx;
}
}
YAML::Node& thingByName(const std::string& name)
{
return things[names[name]];
}
void yy::HeaderParser::error(std::string const& err)
{
@ -160,56 +186,71 @@
%start header;
header:
"{" declarations "}"
"{" declarations "}" postamble
;
postamble:
%empty
| postamble EXECUTOR_ONLY
;
declarations:
%empty
| declarations comments declaration rcomment
{
if($3.size())
{
addComment($3, true, $2, $4);
yamlout << $3;
}
}
| declarations declaration
;
%type <std::string> comments;
comments:
%empty { $$ = ""; }
| comments COMMENT
{ $$ = concatComments($1, $2); }
;
%type <std::string> rcomment;
rcomment:
%empty { $$ = ""; }
| RIGHTCOMMENT
;
declaration:
enum ";"
| struct ";"
| typedef ";"
| lowmem ";"
| trap ";"
| function ";"
| size_assertion ";"
enum_decl
| struct_decl
| typedef
| lowmem
| trap
| function
| size_assertion
| executor_only
;
enum:
"enum" "{" enum_values "}"
enum_decl:
comments enum ";" rcomment
{
$$ = wrap("enum", wrap("values", sequence($3)));
addComment($2, true, $1, $4);
declare($2);
}
;
%type <YAML::Node> enum;
enum:
"enum" optional_identifier "{" enum_values "}"
{
YAML::Node node;
if(!$2.empty())
node["name"] = $2;
node["values"] = sequence($4);
$$ = wrap("enum", node);
}
;
%type <std::vector<YAML::Node>> enum_values;
enum_values:
%empty { }
| enum_values1
| enum_values1 ","
;
%type <std::vector<YAML::Node>> enum_values1;
enum_values1:
comments enum_value rcomment
{
@ -225,6 +266,7 @@ enum_values1:
}
;
%type <YAML::Node> enum_value;
enum_value:
IDENTIFIER
{
@ -237,6 +279,7 @@ enum_value:
}
;
%type <std::string> expression;
expression:
INTLIT
| CHARLIT
@ -245,18 +288,60 @@ expression:
auto q = [](const std::string& a) { return a.substr(1, a.size()-2); };
$$ = "'" + q($3) + q($5) + q($7) + q($9) + "'";
}
| IDENTIFIER
| "-" expression { $$ = "-" + $2; }
| "(" expression ")" { $$ = $2; }
;
struct:
"struct" IDENTIFIER "{" struct_members "}"
struct_decl:
comments struct ";" rcomment
{
YAML::Node node;
node["name"] = $2;
node["members"] = sequence($4);
$$ = wrap("struct", node);
addComment($2, true, $1, $4);
declare($2);
}
;
%type <YAML::Node> struct;
struct:
struct_or_union IDENTIFIER optional_struct_body
{
YAML::Node node;
node["name"] = $2;
if($3)
{
node["members"] = sequence(*$3);
$$ = wrap($1 ? "union" : "struct", node);
}
else
$$ = wrap("forward_struct", node);
}
| struct_or_union "{" struct_members "}"
{
YAML::Node node;
node["members"] = sequence($3);
$$ = wrap($1 ? "union" : "struct", node);
}
;
%type <std::optional<std::vector<YAML::Node>>> optional_struct_body;
optional_struct_body:
%empty {}
| "{" struct_members "}" { $$ = $2; }
;
%type <std::string> optional_identifier;
optional_identifier:
%empty {}
| IDENTIFIER
;
%type <bool> struct_or_union;
struct_or_union:
"struct" { $$ = false; }
| "union" { $$ = true; }
;
%type <std::vector<YAML::Node>> struct_members;
struct_members:
%empty { $$ = {}; }
| "GUEST_STRUCT" ";" { $$ = {}; }
@ -264,84 +349,250 @@ struct_members:
{ $$ = std::move($1); $$.push_back($2); }
;
%type <YAML::Node> struct_member;
struct_member:
comments type_pre IDENTIFIER type_post ";" rcomment
comments type_pre type_op IDENTIFIER type_post ";" rcomment
{
$$["name"] = $3;
$$["name"] = $4;
$$["type"] = $2 + $3 + $5;
addComment($$, false, $1, $7);
}
;
%type <std::string> type;
type:
type_pre type_post
type_pre type_op type_post { $$ = $1 + $2 + $3; }
;
%type <std::string> type_pre;
type_pre:
"GUEST" "<" type ">"
"GUEST" "<" type ">" { $$ = $3; }
| IDENTIFIER
| intlike_type
| type_pre "*"
| "const" type_pre
| enum
| struct
{
if($1 != 5)
$1 &= ~1;
switch($1)
{
case 0: $$ = "int32_t"; break;
case 2: $$ = "uint32_t"; break;
case 4: $$ = "char"; break;
case 5: $$ = "int8_t"; break;
case 6: $$ = "uint8_t"; break;
case 8: $$ = "int16_t"; break;
case 10: $$ = "uint16_t"; break;
case 16: $$ = "int32_t"; break;
case 18: $$ = "uint32_t"; break;
default: $$ = "invalid_int_type"; break;
}
}
| "const" type_pre { $$ = "const " + $2; }
;
%type <std::string> type_op;
type_op:
%empty {}
| type_op "*" { $$ = $1 + "*"; }
;
%type <int> intlike_type;
intlike_type:
intlike_type_elem
| intlike_type intlike_type_elem
intlike_type_elem
| intlike_type intlike_type_elem { $$ = $1 | $2; }
;
%type <int> intlike_type_elem;
intlike_type_elem:
INT
| UNSIGNED
| SHORT
| LONG
| CHAR
| SIGNED
INT { $$ = 0; }
| SIGNED { $$ = 1; }
| UNSIGNED { $$ = 2; }
| CHAR { $$ = 4; }
| SHORT { $$ = 8; }
| LONG { $$ = 16; }
;
%type <std::string> type_post;
type_post:
%empty
| type_post "[" expression "]"
%empty {}
| type_post "[" expression "]" { $$ = $1 + "[" + $3 + "]"; }
;
%type <YAML::Node> funptr;
funptr:
"UPP" "<" type "(" argument_list ")" ">"
{
YAML::Node node;
node["return"] = $3;
if($5.size())
node["args"] = $5;
$$ = wrap("funptr", node);
}
;
typedef:
"typedef" type_pre IDENTIFIER type_post
| "using" IDENTIFIER "=" type
| "typedef" "UPP" "<" type "(" argument_list ")" ">" IDENTIFIER
| "using" IDENTIFIER "=" "UPP" "<" type "(" argument_list ")" ">"
comments "typedef" type_pre typedef_declarator_list ";" rcomment
{
bool first = true;
for(auto [typeOpPost, name] : $4)
{
YAML::Node node;
node["name"] = name;
node["type"] = $3 + typeOpPost;
if(first)
addComment(node, false, $1);
first = false;
declare(wrap("typedef", node));
}
addComment(things.back(), true, $6);
}
| comments "typedef" complex_type typedef_declarator_list ";" rcomment
{
std::string typeName = "";
if($3.begin()->second["name"])
typeName = $3.begin()->second["name"].as<std::string>();
if(typeName.empty())
{
for(auto [typeOpPost, name] : $4)
{
if(typeOpPost.empty())
{
typeName = name;
break;
}
}
if(typeName.empty())
{
std::ostringstream str;
str << "_anonymous" << ++gAnonymousIndex; // FIXME: file name?
typeName = str.str();
}
$3.begin()->second["name"] = typeName;
}
declare($3);
bool first = true;
for(auto [typeOpPost, name] : $4)
{
if(name == typeName)
{
if(!typeOpPost.empty())
error("contradictory: " + name);
}
else
{
YAML::Node node;
node["name"] = name;
node["type"] = typeName + typeOpPost;
if(first)
addComment(node, false, $1);
first = false;
declare(wrap("typedef", node));
}
}
addComment(things.back(), true, $6);
}
| "using" IDENTIFIER "=" "UPP" "<" type "(" argument_list ")" ">"*/
;
%type <YAML::Node> complex_type;
complex_type:
struct
| enum
| funptr
;
%type <std::vector<std::pair<std::string, std::string>>> typedef_declarator_list;
typedef_declarator_list:
type_op IDENTIFIER type_post
{ $$ = { {$1 + $3, $2} }; }
| typedef_declarator_list "," type_op IDENTIFIER type_post
{ $$ = std::move($1); $$.emplace_back($3 + $5, $4); }
;
%type <YAML::Node> argument_list;
argument_list:
%empty
%empty {}
| argument_list1
;
%type <YAML::Node> argument_list1;
argument_list1:
argument
| argument_list1 "," argument
argument { $$.push_back($1); }
| argument_list1 "," argument { $$ = std::move($1); $$.push_back($3); }
;
%type <YAML::Node> argument;
argument:
type
| type IDENTIFIER
{
$$["type"] = $1;
}
| type_pre type_op IDENTIFIER type_post
{
$$["name"] = $3;
$$["type"] = $1 + $2 + $4;
}
;
lowmem:
"const" "LowMemGlobal" "<" type ">" IDENTIFIER "{" INTLIT "}"
comments "const" "LowMemGlobal" "<" type ">" IDENTIFIER "{" INTLIT "}" ";" rcomment
;
trap:
"DISPATCHER_TRAP" "(" IDENTIFIER "," INTLIT "," IDENTIFIER ")"
| "PASCAL_TRAP" "(" IDENTIFIER "," INTLIT ")"
| "PASCAL_FUNCTION" "(" IDENTIFIER ")"
| "PASCAL_SUBTRAP" "(" IDENTIFIER "," INTLIT "," INTLIT "," IDENTIFIER ")"
"DISPATCHER_TRAP" "(" IDENTIFIER "," INTLIT "," IDENTIFIER ")" ";"
| "PASCAL_TRAP" "(" IDENTIFIER "," INTLIT ")" ";"
{
renameThing("C_"+$3, $3);
thingByName($3).begin()->second["trap"] = $5;
}
| "PASCAL_FUNCTION" "(" IDENTIFIER ")" ";"
| "PASCAL_SUBTRAP" "(" IDENTIFIER "," INTLIT "," INTLIT "," IDENTIFIER ")" ";"
{
renameThing("C_"+$3, $3);
auto& fun = thingByName($3);
fun.begin()->second["dispatcher"] = $9;
fun.begin()->second["trap"] = $5;
fun.begin()->second["selector"] = $7;
}
;
function:
"extern" type_pre IDENTIFIER "(" argument_list ")"
comments "extern" type_pre type_op IDENTIFIER "(" argument_list ")" ";" rcomment
{
YAML::Node node;
node["name"] = $5;
node["return"] = $3 + $4;
if($7.size())
node["args"] = $7;
addComment(node, false, $1, $10);
declare(wrap("function", node));
}
;
size_assertion:
"static_assert" "(" "sizeof" "(" IDENTIFIER ")" EQUAL INTLIT ")"
"static_assert" "(" "sizeof" "(" IDENTIFIER ")" EQUAL INTLIT ")" ";"
{
things[names[$5]].begin()->second["size"] = $8;
}
;
executor_only:
comments EXECUTOR_ONLY
{
if(things.size() && things.back().begin()->first.as<std::string>() == "executor_only")
{
things.back().begin()->second["code"]
= things.back().begin()->second["code"].as<std::string>() + "\n"
+ ($1.empty() ? $2 : "// " + $1 + "\n" + $2);
}
else
{
YAML::Node node;
node["code"] = $1.empty() ? $2 : "// " + $1 + "\n" + $2;
declare(wrap("executor_only", node));
}
}
;
%%

View file

@ -2,14 +2,25 @@
#include <iostream>
#include "yaml-cpp/yaml.h"
extern YAML::Emitter yamlout;
extern std::vector<YAML::Node> things;
extern std::unordered_map<std::string, int> names;
int main()
{
yy::HeaderParser parser;
yamlout << YAML::BeginSeq;
parser.parse();
YAML::Emitter yamlout;
yamlout << YAML::BeginSeq;
bool first = true;
for(const auto& n : things)
{
if(!first)
yamlout << YAML::Newline << YAML::Newline << YAML::Comment("####") << YAML::Newline;
first = false;
yamlout << n;
}
yamlout << YAML::EndSeq;
std::cout << yamlout.c_str() << std::endl;