Git Product home page Git Product logo

cplusplus's Introduction

A compiler front end for the C++ language

cxx-frontend is a work-in-progress compiler frontend for C++23

The compiler frontend is designed to be a powerful tool for developers, enabling them to parse, analyze, and modify C++ source code. This project aims to provide a robust foundation for building a complete C++ frontend, staying up-to-date with the latest language features and standards.

The API Reference is available at https://robertoraggi.github.io/cplusplus/docs/

Changelog and What's New

For updates, improvements, and recent features in cxx-frontend, please consult the Changelog.

Key Features

  • Syntax Analysis: APIs to scan, preprocess, parse, and inspect the syntax of source code, making it a versatile tool for various code analysis tasks.

  • Multi-Language Support: In addition to C++, the library provides APIs for TypeScript and JavaScript.

  • C++-23 Support: Latest language enhancements, syntax, and features (WIP).

Syntax Checker and AST Browser Showcase

Storybook and CodeMirror are used to demonstrate how to create a syntax checker and navigate the Abstract Syntax Tree (AST)

https://robertoraggi.github.io/cplusplus/

Installing from npm

To integrate the latest stable version of the C++ Compiler Frontend bindings into your project, you can install them from npm:

npm install cxx-frontend

Once installed, you can use the bindings in your Node.js or web projects as needed.

Getting Started Using Example Projects

These projects are pre-configured and serve as starting points for various use cases.

For Node.js

npx degit robertoraggi/cplusplus/templates/cxx-parse cxx-parse
cd cxx-parse
npm install
node .

For web-based applications, use these commands to clone, set up, and start a development server:

npx degit robertoraggi/cplusplus/templates/cxx-browser-esm-vite cxx-browser-esm-vite
cd cxx-browser-esm-vite
npm install
npm run dev

Build the npm package (requires docker)

# prepare the package
npm ci

# compile WASM and TypeScript code
npm run build:cxx-frontend

Build for WASM/WASI (requires docker)

npm ci
npm run build:wasi

# run the C++ front end CLI tool using wasmtime
wasmtime \
  --mapdir=/::build.wasi/install \
  --mapdir tests::tests \
  build.wasi/install/usr/bin/cxx.wasm -- \
  tests/manual/source.cc -ast-dump

Native Build and CLI tools

On Linux, macOS and Windows:

# install the python packages required to run the unit tests (optional)
pip install -r tests/unit_tests/requirements.txt

# configure the source code
cmake . \
 -G Ninja \
 -B build \
 -DCMAKE_BUILD_TYPE=Release \
 -DCXX_INTERPROCEDURAL_OPTIMIZATION=1

# build
cmake --build build

# run the unit tests
cd build
ctest --progress

Serialize the AST

Use -emit-ast to serialize the AST of a C++ program to a flatbuffer binary file

# serialize the AST
$ ./build/src/frontend/cxx -emit-ast source.cc -o source.ast

You can use any flatbuffers supported decoder to read the AST, e.g.

# Use flatc to dump the AST to JSON
$ ./build/_deps/flatbuffers-build/flatc --raw-binary -t build/src/parser/cxx/ast.bfbs  -- source.ast

$ ll source.*
source.ast source.cc source.json

License

Copyright (c) 2024 Roberto Raggi [email protected]

Licensed under the MIT license.

cplusplus's People

Contributors

dependabot[bot] avatar github-actions[bot] avatar haraldf avatar robertoraggi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cplusplus's Issues

cxx doesn't report missing file passed for parsing

If we pass an nonexistent filename to cxx it doesn't report it.

./cxx nonexistent.cpp -ast-dump
translation-unit

I was expecting something like:

./cxx nonexistent.cpp -ast-dump
error: file "nonexistent.cpp" not found

Preprocessor macro problem

While testing some files I've used to test https://github.com/tyfkda/xcc I found one that cxx stil can't handle:

#define FOO(x)  {x}

FOO(
#if 1
    bar
#else
    qux
#endif
)
g++ -E foo-if.c
# 1 "foo-if.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "foo-if.c"
{bar}
cxx -E foo-if.c
# 1 "foo-if.c"
{
# 5 "foo-if.c"
bar

Notice that cxx is eating the closing brace !

Fail to parse expression inside parenthesis for post increment/decrement

Here is a sample test to show the problem:

int fib(int n)
{
    if(n < 2) return 1;
    return fib(n-2)+fib(n-1);
}

int addOneFirst(int &n)
{
	return ++(n);
}

int addOneAfter(int &n)
{
	return (n)++;
}

int minusOneFirst(int &n)
{
	return --(n);
}

int minusOneAfter(int &n)
{
	return (n)--;
}

Output:

test.cpp:14:14: expected an expression
	return (n)++;
	            ^
test.cpp:24:14: expected an expression
	return (n)--;
	            ^

expected a declaration

While testing cxx with this project https://github.com/peter-winter/ctpg I'm getting this error:

/usr/bin/time ./cxx ctpg/examples/ctjs.cpp -fsyntax-only -toolchain linux -Ictpg/examples/../include
ctpg/examples/ctjs.cpp:455:1: expected a declaration

^
Command exited with non-zero status 1
1.90user 0.04system 0:01.95elapsed 99%CPU (0avgtext+0avgdata 60044maxresident)k
0inputs+0outputs (0major+15748minor)pagefaults 0swaps

clang-16 and g++-13 have no problem with it:

clang-16-env /usr/bin/time clang++ ctpg/examples/ctjs.cpp -fsyntax-only  -Ictpg/examples/../include
1.99user 0.08system 0:02.09elapsed 99%CPU (0avgtext+0avgdata 186508maxresident)k
0inputs+0outputs (0major+33676minor)pagefaults 0swaps

Line 455 is the end of file ctpg/examples/ctjs.cpp .

Fail to parse cppfront

Trying to parse https://github.com/hsutter/cppfront I'm getting several errors/warnings ?

./cxx cppfront/source/cppfront.cpp
cppfront/source/../include/cpp2util.h:1986:2: skipped #line directive
#line 9999
 ^
cppfront/source/reflect.h:11:2: skipped #line directive
#line 1 "reflect.h2"
 ^
...
cppfront/source/../include/cpp2util.h:856:3: expected a compound statement
  noexcept(CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,__VA_ARGS__)) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) \
  ^
...
cppfront/source/reflect.h:791:137: expected a statement
        if (([_0 = 0, _1 = index, _2 = CPP2_UFCS(ssize)(metafunction_args)]{ return cpp2::cmp_less_eq(_0,_1) && cpp2::cmp_less(_1,_2); }())) {
                                                                                                                                        ^
...
cppfront/source/../include/cpp2util.h:809:25: expected a requirement parameter
   requires { requires  requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...); }; \
                        ^
...
cppfront/source/sema.h:24:1: expected a statement
namespace cpp2 {
^
cppfront/source/sema.h:29:24: expected '}'
    assert(n.is_type());
                       ^
cppfront/source/sema.h:201:1: expected a statement
auto is_definite_initialization(token const* t)
^
cppfront/source/sema.h:234:1: expected a statement
auto is_definite_last_use(token const* t)
^
cppfront/source/to_cpp1.h:26:1: expected a statement
namespace cpp2 {
^
cppfront/source/to_cpp1.h:30:1: expected a statement
auto cmdline_processor::print(std::string_view s, int width)
^
cppfront/source/to_cpp1.h:46:1: expected a statement
auto pad(int padding)
^
cppfront/source/to_cpp1.h:192:15: expected '}'
    o << file ;
              ^
cppfront/source/cppfront.cpp:116:1: expected '}'

^

Segmentation fault when parsing JUCE

While testing cxx with this project https://github.com/juce-framework/JUCE I'm getting a segfault with the command shown bellow:

gdb --args ../build/src/frontend/cxx JUCE/modules/juce_core/juce_core.cpp -fsyntax-only -toolchain linux -DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 -IJUCE/modules/juce_core/..
GNU gdb (Ubuntu 10.2-0ubuntu1~18.04~2) 10.2
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ../build/src/frontend/cxx...
(gdb) r
Starting program: cplusplus-parser-dad/build/src/frontend/cxx JUCE/modules/juce_core/juce_core.cpp -fsyntax-only -toolchain linux -DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 -IJUCE/modules/juce_core/..

Program received signal SIGSEGV, Segmentation fault.
std::_Rb_tree<cxx::Name const*, std::pair<cxx::Name const* const, cxx::Symbol*>, std::_Select1st<std::pair<cxx::Name const* const, cxx::Symbol*> >, std::less<cxx::Name const*>, std::allocator<std::pair<cxx::Name const* const, cxx::Symbol*> > >::_M_begin (this=0x10) at /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tree.h:745
745		  (this->_M_impl._M_header._M_parent);
(gdb) bt
#0  std::_Rb_tree<cxx::Name const*, std::pair<cxx::Name const* const, cxx::Symbol*>, std::_Select1st<std::pair<cxx::Name const* const, cxx::Symbol*> >, std::less<cxx::Name const*>, std::allocator<std::pair<cxx::Name const* const, cxx::Symbol*> > >::_M_begin (this=0x10) at /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tree.h:745
#1  0x000055555581540d in std::_Rb_tree<cxx::Name const*, std::pair<cxx::Name const* const, cxx::Symbol*>, std::_Select1st<std::pair<cxx::Name const* const, cxx::Symbol*> >, std::less<cxx::Name const*>, std::allocator<std::pair<cxx::Name const* const, cxx::Symbol*> > >::equal_range (this=0x10, __k=@0x7fffffffa950: 0x555558b8c0a0)
    at /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tree.h:2001
#2  0x000055555581532d in std::multimap<cxx::Name const*, cxx::Symbol*, std::less<cxx::Name const*>, std::allocator<std::pair<cxx::Name const* const, cxx::Symbol*> > >::equal_range (this=0x10, __x=@0x7fffffffa950: 0x555558b8c0a0)
    at /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_multimap.h:1048
#3  0x0000555555809db9 in cxx::Scope::get (this=0x0, name=0x555558b8c0a0)
    at cplusplus-parser-dad/src/parser/cxx/scope.h:52
#4  0x00005555557fe7d8 in cxx::Parser::parse_class_head (this=0x7fffffffc0b8, classHead=...)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:9090
#5  0x00005555557fe034 in cxx::Parser::parse_class_specifier(cxx::ClassSpecifierAST*&, cxx::Parser::DeclSpecs&, std::vector<cxx::TemplateDeclarationAST*, std::allocator<cxx::TemplateDeclarationAST*> > const&)::$_0::operator()() const (
    this=0x7fffffffac78)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:8958
#6  0x00005555557ebca6 in cxx::Parser::parse_class_specifier (this=0x7fffffffc0b8, yyast=@0x7fffffffade8: 0x0, 
    specs=..., templateDeclarations=std::vector of length 0, capacity 0)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:8971
#7  0x00005555557f32be in cxx::Parser::parse_class_specifier (this=0x7fffffffc0b8, yyast=@0x7fffffffade8: 0x0, 
    specs=...) at cplusplus-parser-dad/src/parser/cxx/parser.cc:8931
#8  0x00005555557f1de0 in cxx::Parser::parse_defining_type_specifier (this=0x7fffffffc0b8, 
    yyast=@0x7fffffffb0b0: 0x0, specs=...)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:5388
--Type <RET> for more, q to quit, c to continue without paging--
#9  0x00005555557f1632 in cxx::Parser::parse_decl_specifier (this=0x7fffffffc0b8, yyast=@0x7fffffffb0b0: 0x0, 
    specs=...) at cplusplus-parser-dad/src/parser/cxx/parser.cc:5159
#10 0x00005555557e59ea in cxx::Parser::parse_decl_specifier_seq (this=0x7fffffffc0b8, 
    yyast=@0x7fffffffb1d8: 0x5555577cd9f0, specs=...)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:5183
#11 0x00005555557ede42 in cxx::Parser::parse_simple_declaration(cxx::DeclarationAST*&, std::vector<cxx::TemplateDeclarationAST*, std::allocator<cxx::TemplateDeclarationAST*> > const&, cxx::Parser::BindingContext)::$_0::operator()() const (this=0x7fffffffb1c0)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:4673
#12 0x00005555557e73d2 in cxx::Parser::parse_simple_declaration (this=0x7fffffffc0b8, yyast=@0x5555577cd8f0: 0x0, 
    templateDeclarations=std::vector of length 1, capacity 1 = {...}, ctx=cxx::Parser::BindingContext::kTemplate)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:4679
#13 0x00005555557e62be in cxx::Parser::parse_template_declaration_body (this=0x7fffffffc0b8, 
    yyast=@0x5555577cd8f0: 0x0, templateDeclarations=std::vector of length 1, capacity 1 = {...})
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:4269
#14 0x0000555555802615 in cxx::Parser::parse_template_declaration (this=0x7fffffffc0b8, 
    yyast=@0x7fffffffb468: 0x5555577cd8c0, templateDeclarations=std::vector of length 1, capacity 1 = {...})
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:9974
#15 0x00005555557e77d6 in cxx::Parser::parse_template_declaration (this=0x7fffffffc0b8, 
    yyast=@0x7fffffffb468: 0x5555577cd8c0)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:9930
#16 0x00005555557fee8f in cxx::Parser::parse_member_declaration (this=0x7fffffffc0b8, yyast=@0x7fffffffb578: 0x0)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:9183
#17 0x00005555557fe44d in cxx::Parser::parse_member_specification (this=0x7fffffffc0b8, yyast=@0x7fffffffb578: 0x0)
    at cplusplus-parser-dad/src/parser/cxx/parser.cc:9152
#18 0x00005555557fe26e in cxx::Parser::parse_class_body (this=0x7fffffffc0b8, yyast=@0x5555577cc5c0: 0x5555577cc870)

clang16 parse it fine:

clang-16-env clang++ /home/mingo/dev/c/A_programming-languages/JUCE/modules/juce_core/juce_core.cpp -fsyntax-only -DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 -I/home/mingo/dev/c/A_programming-languages/JUCE/modules/juce_core/..
## no error

expected a statement

With this issue solved now I'm getting the error shown bellow (that is a reduced case of this #309 (comment)).

void test()
{
	int i;
	( ({ long __cpu = ((long) i); }));
}
g++ -fsyntax-only test-bloc-in-parens.cpp
# no error
cxx test-bloc-in-parens.cpp
createSourceFile: test-bloc-in-parens.cpp
test-bloc-in-parens.cpp:4:33: expected a statement
	( ({ long __cpu = ((long) i); }));
	                               ^

Do not recognize "#pragma one"

While trying to parse llama.cpp I'm getting this errors:

./cxx-O2 llama.cpp/llama.cpp -ast-dump
llama.cpp/unicode.h:1:1: expected a declaration
#pragma once
^
llama.cpp/unicode.h:1:2: expected a declaration
#pragma once
 ^
cplusplus-parser/build/src/frontend/../lib/wasi-sysroot/include/assert.h:16:1: expected a declaration
extern "C" {
^

return __extension__ (__m128){ 0.0f, 0.0f, 0.0f, 0.0f };

While testing cxx with https://github.com/PX4/eigen/tree/3.4 :

/* The Intel API is flexible enough that we must allow aliasing with other
   vector types, and their scalar components.  */
typedef float __m128 __attribute__ ((__vector_size__ (16), __may_alias__));

/* Create a vector of zeros.  */
extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_setzero_ps (void)
{
  return __extension__ (__m128){ 0.0f, 0.0f, 0.0f, 0.0f };
}

Output:

g++ -fsyntax-only test-m128.cpp
#no error

clang++ -fsyntax-only test-m128.cpp
test-m128.cpp:6:74: warning: unknown attribute '__artificial__' ignored [-Wunknown-attributes]
extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
                                                                         ^
1 warning generated.

cxx -fsyntax-only -toolchain linux test-m128.cpp
test-m128.cpp:9:32: expected ';'
  return __extension__ (__m128){ 0.0f, 0.0f, 0.0f, 0.0f };
                               ^
test-m128.cpp:9:57: expected ';'
  return __extension__ (__m128){ 0.0f, 0.0f, 0.0f, 0.0f };
                                                        ^

Testing with examples from https://en.cppreference.com/w/

Using the Lua script shown bellow to extract the code examples from https://en.cppreference.com/w/ I'm getting this results:

#cxx
Total files scanned     :	5629
Total files with code   :	2889
Total files failed code :	172

#clang-17
Total files scanned     :	5629
Total files with code   :	2889
Total files failed code :	266

#g++-13
Total files scanned     :	5629
Total files with code   :	2889
Total files failed code :	197

#circle-200
Total files scanned     :	5629
Total files with code   :	2889
Total files failed code :	474
local base_dir = "/home/mingo/.local/share/Zeal/Zeal/docsets/C++.docset/Contents/Resources/Documents/en.cppreference.com/w/cpp/";

local cppCodeFName = "/tmp/cppCode.cpp";
--local cxx_cmd = "../build/src/frontend/cxx -fsyntax-only -toolchain linux " .. cppCodeFName;
--local cxx_cmd = "/usr/bin/time ../build-release/src/frontend/cxx -fsyntax-only -toolchain linux " .. cppCodeFName;
local cxx_cmd = "/usr/bin/time ./cxx -fsyntax-only -toolchain linux " .. cppCodeFName;
--local cxx_cmd = "clang-17-env /usr/bin/time clang++ -std=c++23 -fsyntax-only " .. cppCodeFName;
--local cxx_cmd = "clang-17-env /usr/bin/time clang++ -fsyntax-only " .. cppCodeFName;
--local cxx_cmd = "gcc-13-env /usr/bin/time g++ -std=c++23 -fsyntax-only " .. cppCodeFName;
--local cxx_cmd = "gcc-13-env /usr/bin/time g++ -fsyntax-only " .. cppCodeFName;
--local cxx_cmd = "/usr/bin/time timeout 3s circle  -std=c++2b -fsyntax-only " .. cppCodeFName;

local code_re = "<div class=\"t%-example%-live%-link\">.-<div class=\"cpp source%-cpp\">(.-)</pre></div>";

local find_cmd = "find " .. base_dir .. " -name '*.html'";
local start_t = os.time();

local html_list = {};
for fname in io.popen(find_cmd, "r"):lines("l") do
	table.insert(html_list, fname);
end
table.sort(html_list);

local count_with_code = 0;
local fname_with_code_failed = {};
for idx, fname in ipairs(html_list) do
	print(fname);

	local html = io.open(fname, "r"):read("a");
	for code in html:gmatch(code_re) do
		code = code:gsub("%b<>", "");
		code = code:gsub("&nbsp;", " ");
		code = code:gsub("&lt;", "<");
		code = code:gsub("&gt;", ">");
		code = code:gsub("&amp;", "&");

		--print("//====Start");
		--print(code);
		--print("//====End");

		local fd = io.open(cppCodeFName, "w");
		fd:write(code);
		fd:close();
		count_with_code = count_with_code + 1;
		print("==CHECK==")
		print(cxx_cmd);
		io.stdout:flush();
		local rc, rc_type, rc_code = os.execute(cxx_cmd);
		if rc_code == 0 then
			print("==rc:OK==")
		else
			table.insert(fname_with_code_failed, idx);
			print("==rc:FAILED==")
			print("//====Start");
			print(code);
			print("//====End");
		end
	end

end
local end_t = os.time();
print("elapsed time: ", os.difftime(end_t, start_t));
print("Total files scanned     :", #html_list);
print("Total files with code   :", count_with_code);
print("Total files failed code :", #fname_with_code_failed);
for idx, fname_idx in ipairs(fname_with_code_failed) do
	print(html_list[fname_idx]);
end

See attached the output for cxx and clang-17:
test-cpp-reference-examples-cxx.output.zip
test-cpp-reference-examples-clang-17-std23.output.zip

expected a declaration

While testing cxx with https://c9x.me/qscm/data/qscm.c I found that cxx get lost with this extracted test (heavy on macros):

typedef long V;

#define L(n) L_(n, E)
#define A a_(E)
#define B(x,y) (E=C(x,E), B_(y, &E))
#define F(n) C((V)f##n, E)
#define Z1(f) Zn(f, 0)
#define Z(f,a) Zn(f, C(a,0))
#define Z3(f,a,b) Zn(f, C(a,C(b,0)))
#define Z4(f,a,b,c) Zn(f, C(a,C(b,C(c,0))))
#define J return
#define D(x,y) V f##x(V E){J y;}

int putchar(int c) {return 0;}
int getchar() {return 0;}
V malloc(long) {return 0;}

V C(V a,V d){return 0;}
V a_(V x){J*(V*)x;}
V d_(V x){J*((V*)x+1);}
V B_(V x,V *e){*e=d_(*e);J x;}
V L_(V n,V e){while(--n)e=d_(e);J a_(e);}
V Zn(V x,V a){return 0;}

D(g,*(char *)A)
D(s,*(char *)L(2)=A)
D(n,(V)malloc(A))
D(c,C(L(2),A))
D(a,a_(A))
D(d,d_(A))
D(i,getchar())
D(o,putchar(A))
#define X(x) (V)&(V[2]){(V)f##x}

V qget=X(g);
g++ -fsyntax-only test-qscm-macro.cpp
//no errors
cxx test-qscm-macro.cpp
test-qscm-macro.cpp:33:24: expected a declaration
#define X(x) (V)&(V[2]){(V)f##x}
                       ^
test-qscm-macro.cpp:33:25: expected a declaration
#define X(x) (V)&(V[2]){(V)f##x}
                        ^
test-qscm-macro.cpp:33:27: expected a declaration
#define X(x) (V)&(V[2]){(V)f##x}
                          ^
test-qscm-macro.cpp:33:32: expected a declaration
#define X(x) (V)&(V[2]){(V)f##x}
                               ^

expected a declaration "_Noreturn void __wasi_proc_exit("

While trying to parse this project https://github.com/mingodad/parsertl-playground we get this output:

/usr/bin/time ./cxx parsertl-playground/playground/playground.cpp -fsyntax-only -Iparsertl-playground
cplusplus-parser/build/src/frontend/../lib/wasi-sysroot/include/sys/mman.h:2:2: #error "WASI lacks a true mmap; to enable minimal mmap emulation, \
compile with -D_WASI_EMULATED_MMAN and link with -lwasi-emulated-mman"
#error "WASI lacks a true mmap; to enable minimal mmap emulation, \
 ^
cplusplus-parser/build/src/frontend/../lib/wasi-sysroot/include/wasi/api.h:1987:11: expected a declaration
_Noreturn void __wasi_proc_exit(
          ^
Command exited with non-zero status 1
3.78user 0.08system 0:03.87elapsed 99%CPU (0avgtext+0avgdata 102296maxresident)k
0inputs+0outputs (0major+28328minor)pagefaults 0swaps

Changing "specs/grammar.txt" to an EBNF understood by https://www.bottlecaps.de/rr/ui

If we change "specs/grammar.txt" to an EBNF understood by https://www.bottlecaps.de/rr/ui we can get a nice navigable railroad diagram representation of it that can help document/develop/debug this project grammar, follow the instructions shown bellow:

//
// EBNF to be viewd at https://www.bottlecaps.de/rr/ui
//
// Copy and paste this at https://www.bottlecaps.de/rr/ui in the 'Edit Grammar' tab
// then click the 'View Diagram' tab.
//

//
//To facilitate start navigating
//

cplusplus ::=
	preprocessing-file? translation-unit

//== lex.tex

n-char ::=
     "{any member of the translation character set except the \unicode{007d}{right curly bracket} or new-line character}"

n-char-sequence ::=
    n-char
  | n-char-sequence n-char

named-universal-character ::=
    "\N{" n-char-sequence "}"

hex-quad ::=
    hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit

simple-hexadecimal-digit-sequence ::=
    hexadecimal-digit
  | simple-hexadecimal-digit-sequence hexadecimal-digit

universal-character-name ::=
    "\u" hex-quad
  | "\U" hex-quad hex-quad
  | "\u{" simple-hexadecimal-digit-sequence "}"
  | named-universal-character

preprocessing-token ::=
    header-name
  | "import"
  | "module"
  | "export"
  | identifier
  | pp-number
  | character-literal
  | user-defined-character-literal
  | string-literal
  | user-defined-string-literal
  | preprocessing-op-or-punc
  | "{each non-whitespace character that cannot be one of the above}"

//token ::=
//    identifier
//  | keyword
//  | literal
//  | operator-or-punctuator

header-name ::=
    "<" h-char-sequence ">"
  | '"' q-char-sequence '"'

h-char-sequence ::=
    h-char
  | h-char-sequence h-char

h-char ::=
    "{any member of the translation character set except new-line and \unicode{003e}{greater-than sign}}"

q-char-sequence ::=
    q-char
  | q-char-sequence q-char

q-char ::=
    "{any member of the translation character set except new-line and \unicode{0022}{quotation mark}}"

pp-number ::=
    digit
  | "." digit
  | pp-number identifier-continue
  | pp-number "'" digit
  | pp-number "'" nondigit
  | pp-number "e" sign
  | pp-number "E" sign
  | pp-number "p" sign
  | pp-number "P" sign
  | pp-number "."

identifier ::=
    identifier-start
  | identifier identifier-continue

identifier-start ::=
    nondigit
  | "{an element of the translation character set with the Unicode property XID_Start}"

identifier-continue ::=
    digit
  | nondigit
  | "{an element of the translation character set with the Unicode property XID_Continue}"

nondigit ::=
    "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m"
  | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
  | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M"
  | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "_"

digit ::=
    "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

keyword ::=
    "{any identifier listed in lex.key}"
  | "import"
  | "module"
  | "export"

preprocessing-op-or-punc ::=
    preprocessing-operator
  | operator-or-punctuator

preprocessing-operator ::=
    "#" | "##" | "%:" | "%:%:"

operator-or-punctuator ::=
    "{" | "}" | "[" | "]" | "(" | ")"
  | "<:" | ":>" | "<%" | "%>" | ";" | ":" | "..."
  | "?" | "::" | "." | ".*" | "->" | "->*" | "~"
  | "!" | "+" | "-" | "*" | "/" | "%" | "^" | "&" | "|"
  | "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "&=" | "|="
  | "==" | "!=" | "<" | ">" | "<=" | ">=" | "<=>" | "&&" | "||"
  | "<<" | ">>" | "<<=" | ">>=" | "++" | "--" | ","
  | "and" | "or" | "xor" | "not" | "bitand" | "bitor" | "compl"
  | "and_eq" | "or_eq" | "xor_eq" | "not_eq"

literal ::=
    integer-literal
  | character-literal
  | floating-point-literal
  | string-literal
  | boolean-literal
  | pointer-literal
  | user-defined-literal

integer-literal ::=
    binary-literal integer-suffix?
  | octal-literal integer-suffix?
  | decimal-literal integer-suffix?
  | hexadecimal-literal integer-suffix?

binary-literal ::=
    "0b" binary-digit
  | "0B" binary-digit
  | binary-literal "'"? binary-digit

octal-literal ::=
    "0"
  | octal-literal "'"? octal-digit

decimal-literal ::=
    nonzero-digit
  | decimal-literal "'"? digit

hexadecimal-literal ::=
    hexadecimal-prefix hexadecimal-digit-sequence

binary-digit ::=
    "0" | "1"

octal-digit ::=
    "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7"

nonzero-digit ::=
    "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

hexadecimal-prefix ::=
    "0x" | "0X"

hexadecimal-digit-sequence ::=
    hexadecimal-digit
  | hexadecimal-digit-sequence "'"? hexadecimal-digit

hexadecimal-digit ::=
    "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
  | "a" | "b" | "c" | "d" | "e" | "f"
  | "A" | "B" | "C" | "D" | "E" | "F"

integer-suffix ::=
    unsigned-suffix long-suffix?
  | unsigned-suffix long-long-suffix?
  | unsigned-suffix size-suffix?
  | long-suffix unsigned-suffix?
  | long-long-suffix unsigned-suffix?
  | size-suffix unsigned-suffix?

unsigned-suffix ::=
    "u" | "U"

long-suffix ::=
    "l" | "L"

long-long-suffix ::=
    "ll" | "LL"

size-suffix ::=
   "z" | "Z"

character-literal ::=
    encoding-prefix? "'" c-char-sequence "'"

encoding-prefix ::=
    "u8" | "u" | "U" | "L"

c-char-sequence ::=
    c-char
  | c-char-sequence c-char

c-char ::=
    basic-c-char
  | escape-sequence
  | universal-character-name

basic-c-char ::=
    "{any member of the translation character set except the \unicode{0027}{apostrophe},}"
        "{\unicode{005c}{reverse solidus}, or new-line character}"

escape-sequence ::=
    simple-escape-sequence
  | numeric-escape-sequence
  | conditional-escape-sequence

simple-escape-sequence ::=
    "\" simple-escape-sequence-char

simple-escape-sequence-char ::=
    "'" | '"' | "?" | "\" | "a" | "b" | "f" | "n" | "r" | "t" | "v"

numeric-escape-sequence ::=
    octal-escape-sequence
  | hexadecimal-escape-sequence

simple-octal-digit-sequence ::=
    octal-digit
  | simple-octal-digit-sequence octal-digit

octal-escape-sequence ::=
    "\" octal-digit
  | "\" octal-digit octal-digit
  | "\" octal-digit octal-digit octal-digit
  | "\o{" simple-octal-digit-sequence "}"

hexadecimal-escape-sequence ::=
    "\x" simple-hexadecimal-digit-sequence
  | "\x{" simple-hexadecimal-digit-sequence "}"

conditional-escape-sequence ::=
    "\" conditional-escape-sequence-char

conditional-escape-sequence-char ::=
    '{any member of the basic character set that is not an octal-digit, a simple-escape-sequence-char, or the characters "N", "o", "u", "U", or "x"}'

floating-point-literal ::=
    decimal-floating-point-literal
  | hexadecimal-floating-point-literal

decimal-floating-point-literal ::=
    fractional-constant exponent-part? floating-point-suffix?
  | digit-sequence exponent-part floating-point-suffix?

hexadecimal-floating-point-literal ::=
    hexadecimal-prefix hexadecimal-fractional-constant binary-exponent-part floating-point-suffix?
  | hexadecimal-prefix hexadecimal-digit-sequence binary-exponent-part floating-point-suffix?

fractional-constant ::=
    digit-sequence? "." digit-sequence
  | digit-sequence "."

hexadecimal-fractional-constant ::=
    hexadecimal-digit-sequence? "." hexadecimal-digit-sequence
  | hexadecimal-digit-sequence "."

exponent-part ::=
    "e" sign? digit-sequence
  | "E" sign? digit-sequence

binary-exponent-part ::=
    "p" sign? digit-sequence
  | "P" sign? digit-sequence

sign ::=
    "+" | "-"

digit-sequence ::=
    digit
  | digit-sequence "'"? digit

floating-point-suffix ::=
    "f" | "l" | "f16" | "f32" | "f64" | "f128" | "bf16" | "F" | "L" | "F16" | "F32" | "F64" | "F128" | "BF16"

string-literal ::=
    encoding-prefix? '"' s-char-sequence? '"'
  | encoding-prefix? "R" raw-string

s-char-sequence ::=
    s-char
  | s-char-sequence s-char

s-char ::=
    basic-s-char
  | escape-sequence
  | universal-character-name

basic-s-char ::=
    "{any member of the translation character set except the \unicode{0022}{quotation mark},}"
        "{\unicode{005c}{reverse solidus}, or new-line character}"

raw-string ::=
    '"' d-char-sequence? "(" r-char-sequence? ")" d-char-sequence? '"'

r-char-sequence ::=
    r-char
  | r-char-sequence r-char

r-char ::=
    "{any member of the translation character set, except a \unicode{0029}{right parenthesis} followed by}"
        "{the initial d-char-sequence (which may be empty) followed by a \unicode{0022}{quotation mark}}"

d-char-sequence ::=
    d-char
  | d-char-sequence d-char

d-char ::=
    "{any member of the basic character set except:}"
        "{\unicode{0020}{space}, \unicode{0028}{left parenthesis}, \unicode{0029}{right parenthesis}, \unicode{005c}{reverse solidus},}"
        "{\unicode{0009}{character tabulation}, \unicode{000b}{line tabulation}, \unicode{000c}{form feed}, and new-line}"

unevaluated-string ::=
    string-literal

boolean-literal ::=
    "false"
  | "true"

pointer-literal ::=
    "nullptr"

user-defined-literal ::=
    user-defined-integer-literal
  | user-defined-floating-point-literal
  | user-defined-string-literal
  | user-defined-character-literal

user-defined-integer-literal ::=
    decimal-literal ud-suffix
  | octal-literal ud-suffix
  | hexadecimal-literal ud-suffix
  | binary-literal ud-suffix

user-defined-floating-point-literal ::=
    fractional-constant exponent-part? ud-suffix
  | digit-sequence exponent-part ud-suffix
  | hexadecimal-prefix hexadecimal-fractional-constant binary-exponent-part ud-suffix
  | hexadecimal-prefix hexadecimal-digit-sequence binary-exponent-part ud-suffix

user-defined-string-literal ::=
    string-literal ud-suffix

user-defined-character-literal ::=
    character-literal ud-suffix

ud-suffix ::=
    identifier

//== basic.tex

translation-unit ::=
    declaration-seq?
  | global-module-fragment? module-declaration declaration-seq? private-module-fragment?

//== expressions.tex

primary-expression ::=
    literal
  | "this"
  | "(" expression ")"
  | id-expression
  | lambda-expression
  | fold-expression
  | requires-expression

id-expression ::=
    unqualified-id
  | qualified-id
  | pack-index-expression

unqualified-id ::=
    identifier
  | operator-function-id
  | conversion-function-id
  | literal-operator-id
  | "~" type-name
  | "~" computed-type-specifier
  | template-id

qualified-id ::=
    nested-name-specifier "template"? unqualified-id

nested-name-specifier ::=
    "::"
  | type-name "::"
  | namespace-name "::"
  | computed-type-specifier "::"
  | nested-name-specifier identifier "::"
  | nested-name-specifier "template"? simple-template-id "::"

pack-index-expression ::=
    id-expression "..." "[" constant-expression "]"

lambda-expression ::=
    lambda-introducer attribute-specifier-seq? lambda-declarator compound-statement
  | lambda-introducer "<" template-parameter-list ">" requires-clause? attribute-specifier-seq?
         lambda-declarator compound-statement

lambda-introducer ::=
    "[" lambda-capture? "]"

lambda-declarator ::=
    lambda-specifier-seq noexcept-specifier? attribute-specifier-seq? trailing-return-type?
  | noexcept-specifier attribute-specifier-seq? trailing-return-type?
  | trailing-return-type?
  | "(" parameter-declaration-clause ")" lambda-specifier-seq? noexcept-specifier? attribute-specifier-seq?
         trailing-return-type? requires-clause?

lambda-specifier ::=
    "consteval"
  | "constexpr"
  | "mutable"
  | "static"

lambda-specifier-seq ::=
    lambda-specifier
  | lambda-specifier lambda-specifier-seq

lambda-capture ::=
    capture-default
  | capture-list
  | capture-default "," capture-list

capture-default ::=
    "&"
  | "="

capture-list ::=
    capture
  | capture-list "," capture

capture ::=
    simple-capture
  | init-capture

simple-capture ::=
    identifier "..."?
  | "&" identifier "..."?
  | "this"
  | "*" "this"

init-capture ::=
    "..."? identifier initializer
  | "&" "..."? identifier initializer

fold-expression ::=
    "(" cast-expression fold-operator "..." ")"
  | "(" "..." fold-operator cast-expression ")"
  | "(" cast-expression fold-operator "..." fold-operator cast-expression ")"

fold-operator ::=
    "+" | "-" | "*" | "/" | "%" | "^" | "&" | "|" | "<<" | ">>"
  | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "&=" | "|=" | "<<=" | ">>=" | "="
  | "==" | "!=" | "<" | ">" | "<=" | ">=" | "&&" | "||" | "," | ".*" | "->*"

requires-expression ::=
    "requires" requirement-parameter-list? requirement-body

requirement-parameter-list ::=
    "(" parameter-declaration-clause ")"

requirement-body ::=
    "{" requirement-seq "}"

requirement-seq ::=
    requirement
  | requirement requirement-seq

requirement ::=
    simple-requirement
  | type-requirement
  | compound-requirement
  | nested-requirement

simple-requirement ::=
    expression ";"

type-requirement ::=
    "typename" nested-name-specifier? type-name ";"

compound-requirement ::=
    "{" expression "}" "noexcept"? return-type-requirement? ";"

return-type-requirement ::=
    "->" type-constraint

nested-requirement ::=
    "requires" constraint-expression ";"

postfix-expression ::=
    primary-expression
  | postfix-expression "[" expression-list? "]"
  | postfix-expression "(" expression-list? ")"
  | simple-type-specifier "(" expression-list? ")"
  | typename-specifier "(" expression-list? ")"
  | simple-type-specifier braced-init-list
  | typename-specifier braced-init-list
  | postfix-expression "." "template"? id-expression
  | postfix-expression "->" "template"? id-expression
  | postfix-expression "++"
  | postfix-expression "--"
  | "dynamic_cast" "<" type-id ">" "(" expression ")"
  | "static_cast" "<" type-id ">" "(" expression ")"
  | "reinterpret_cast" "<" type-id ">" "(" expression ")"
  | "const_cast" "<" type-id ">" "(" expression ")"
  | "typeid" "(" expression ")"
  | "typeid" "(" type-id ")"

expression-list ::=
    initializer-list

unary-expression ::=
    postfix-expression
  | unary-operator cast-expression
  | "++" cast-expression
  | "--" cast-expression
  | await-expression
  | "sizeof" unary-expression
  | "sizeof" "(" type-id ")"
  | "sizeof" "..." "(" identifier ")"
  | "alignof" "(" type-id ")"
  | noexcept-expression
  | new-expression
  | delete-expression

unary-operator ::=
    "*" | "&" | "+" | "-" | "!" | "~"

await-expression ::=
    "co_await" cast-expression

noexcept-expression ::=
  "noexcept" "(" expression ")"

new-expression ::=
    "::"? "new" new-placement? new-type-id new-initializer?
  | "::"? "new" new-placement? "(" type-id ")" new-initializer?

new-placement ::=
    "(" expression-list ")"

new-type-id ::=
    type-specifier-seq new-declarator?

new-declarator ::=
    ptr-operator new-declarator?
  | noptr-new-declarator

noptr-new-declarator ::=
    "[" expression? "]" attribute-specifier-seq?
  | noptr-new-declarator "[" constant-expression "]" attribute-specifier-seq?

new-initializer ::=
    "(" expression-list? ")"
  | braced-init-list

delete-expression ::=
    "::"? "delete" cast-expression
  | "::"? "delete" "[" "]" cast-expression

cast-expression ::=
    unary-expression
  | "(" type-id ")" cast-expression

pm-expression ::=
    cast-expression
  | pm-expression ".*" cast-expression
  | pm-expression "->*" cast-expression

multiplicative-expression ::=
    pm-expression
  | multiplicative-expression "*" pm-expression
  | multiplicative-expression "/" pm-expression
  | multiplicative-expression "%" pm-expression

additive-expression ::=
    multiplicative-expression
  | additive-expression "+" multiplicative-expression
  | additive-expression "-" multiplicative-expression

shift-expression ::=
    additive-expression
  | shift-expression "<<" additive-expression
  | shift-expression ">>" additive-expression

compare-expression ::=
    shift-expression
  | compare-expression "<=>" shift-expression

relational-expression ::=
    compare-expression
  | relational-expression "<" compare-expression
  | relational-expression ">" compare-expression
  | relational-expression "<=" compare-expression
  | relational-expression ">=" compare-expression

equality-expression ::=
    relational-expression
  | equality-expression "==" relational-expression
  | equality-expression "!=" relational-expression

and-expression ::=
    equality-expression
  | and-expression "&" equality-expression

exclusive-or-expression ::=
    and-expression
  | exclusive-or-expression "^" and-expression

inclusive-or-expression ::=
    exclusive-or-expression
  | inclusive-or-expression "|" exclusive-or-expression

logical-and-expression ::=
    inclusive-or-expression
  | logical-and-expression "&&" inclusive-or-expression

logical-or-expression ::=
    logical-and-expression
  | logical-or-expression "||" logical-and-expression

conditional-expression ::=
    logical-or-expression
  | logical-or-expression "?" expression ":" assignment-expression

  yield-expression ::=
  "co_yield" assignment-expression
  | "co_yield" braced-init-list

throw-expression ::=
    "throw"  assignment-expression?

assignment-expression ::=
    conditional-expression
  | yield-expression
  | throw-expression
  | logical-or-expression assignment-operator initializer-clause

assignment-operator ::=
    "=" | "*=" | "/=" | "%=" | "+=" | "-=" | ">>=" | "<<=" | "&=" | "^=" | "|="

expression ::=
    assignment-expression
  | expression "," assignment-expression

constant-expression ::=
    conditional-expression

//== statements.tex

statement ::=
    labeled-statement
  | attribute-specifier-seq? expression-statement
  | attribute-specifier-seq? compound-statement
  | attribute-specifier-seq? selection-statement
  | attribute-specifier-seq? iteration-statement
  | attribute-specifier-seq? jump-statement
  | declaration-statement
  | attribute-specifier-seq? try-block

init-statement ::=
    expression-statement
  | simple-declaration
  | alias-declaration

condition ::=
    expression
  | attribute-specifier-seq? decl-specifier-seq declarator brace-or-equal-initializer

label ::=
    attribute-specifier-seq? identifier ":"
  | attribute-specifier-seq? "case" constant-expression ":"
  | attribute-specifier-seq? "default" ":"

labeled-statement ::=
    label statement

expression-statement ::=
    expression? ";"

compound-statement ::=
    "{" statement-seq? label-seq? "}"

statement-seq ::=
    statement
  | statement-seq statement

label-seq ::=
    label
  | label-seq label

selection-statement ::=
    "if" "constexpr"? "(" init-statement? condition ")" statement
  | "if" "constexpr"? "(" init-statement? condition ")" statement "else" statement
  | "if" "!"? "consteval" compound-statement
  | "if" "!"? "consteval" compound-statement "else" statement
  | "switch" "(" init-statement? condition ")" statement

iteration-statement ::=
    "while" "(" condition ")" statement
  | "do" statement "while" "(" expression ")" ";"
  | "for" "(" init-statement condition? ";" expression? ")" statement
  | "for" "(" init-statement? for-range-declaration ":" for-range-initializer ")" statement

for-range-declaration ::=
    attribute-specifier-seq? decl-specifier-seq declarator
  | attribute-specifier-seq? decl-specifier-seq ref-qualifier? "[" identifier-list "]"

for-range-initializer ::=
    expr-or-braced-init-list

jump-statement ::=
    "break" ";"
  | "continue" ";"
  | "return" expr-or-braced-init-list? ";"
  | coroutine-return-statement
  | "goto" identifier ";"

coroutine-return-statement ::=
    "co_return" expr-or-braced-init-list? ";"

declaration-statement ::=
    block-declaration

//== declarations.tex

declaration-seq ::=
    declaration
  | declaration-seq declaration

declaration ::=
    name-declaration
  | special-declaration

name-declaration ::=
    block-declaration
  | nodeclspec-function-declaration
  | function-definition
  | template-declaration
  | deduction-guide
  | linkage-specification
  | namespace-definition
  | empty-declaration
  | attribute-declaration
  | module-import-declaration

special-declaration ::=
    explicit-instantiation
  | explicit-specialization
  | export-declaration

block-declaration ::=
    simple-declaration
  | asm-declaration
  | namespace-alias-definition
  | using-declaration
  | using-enum-declaration
  | using-directive
  | static_assert-declaration
  | alias-declaration
  | opaque-enum-declaration

nodeclspec-function-declaration ::=
    attribute-specifier-seq? declarator ";"

alias-declaration ::=
    "using" identifier attribute-specifier-seq? "=" defining-type-id ";"

simple-declaration ::=
    decl-specifier-seq init-declarator-list? ";"
  | attribute-specifier-seq decl-specifier-seq init-declarator-list ";"
  | attribute-specifier-seq? decl-specifier-seq ref-qualifier? "[" identifier-list "]" initializer ";"

static_assert-message ::=
  unevaluated-string
  | constant-expression

static_assert-declaration ::=
  "static_assert" "(" constant-expression ")" ";"
  | "static_assert" "(" constant-expression "," static_assert-message ")" ";"

empty-declaration ::=
    ";"

attribute-declaration ::=
    attribute-specifier-seq ";"

decl-specifier ::=
    storage-class-specifier
  | defining-type-specifier
  | function-specifier
  | "friend"
  | "typedef"
  | "constexpr"
  | "consteval"
  | "constinit"
  | "inline"

decl-specifier-seq ::=
    decl-specifier attribute-specifier-seq?
  | decl-specifier decl-specifier-seq

storage-class-specifier ::=
    "static"
  | "thread_local"
  | "extern"
  | "mutable"

function-specifier ::=
    "virtual"
  | explicit-specifier

explicit-specifier ::=
    "explicit" "(" constant-expression ")"
  | "explicit"

typedef-name ::=
    identifier
  | simple-template-id

type-specifier ::=
  simple-type-specifier
  | elaborated-type-specifier
  | typename-specifier
  | cv-qualifier

type-specifier-seq ::=
    type-specifier attribute-specifier-seq?
  | type-specifier type-specifier-seq

defining-type-specifier ::=
    type-specifier
  | class-specifier
  | enum-specifier

defining-type-specifier-seq ::=
  defining-type-specifier attribute-specifier-seq?
  | defining-type-specifier defining-type-specifier-seq

simple-type-specifier ::=
    nested-name-specifier? type-name
  | nested-name-specifier "template" simple-template-id
  | computed-type-specifier
  | placeholder-type-specifier
  | nested-name-specifier? template-name
  | "char"
  | "char8_t"
  | "char16_t"
  | "char32_t"
  | "wchar_t"
  | "bool"
  | "short"
  | "int"
  | "long"
  | "signed"
  | "unsigned"
  | "float"
  | "double"
  | "void"

type-name ::=
    class-name
  | enum-name
  | typedef-name

computed-type-specifier ::=
    decltype-specifier
  | pack-index-specifier

pack-index-specifier ::=
    typedef-name "..." "[" constant-expression "]"

elaborated-type-specifier ::=
    class-key attribute-specifier-seq? nested-name-specifier? identifier
  | class-key simple-template-id
  | class-key nested-name-specifier "template"? simple-template-id
  | "enum" nested-name-specifier? identifier

decltype-specifier ::=
  "decltype" "(" expression ")"

placeholder-type-specifier ::=
  type-constraint? "auto"
  | type-constraint? "decltype" "(" "auto" ")"

init-declarator-list ::=
    init-declarator
  | init-declarator-list "," init-declarator

init-declarator ::=
    declarator initializer?
  | declarator requires-clause

declarator ::=
    ptr-declarator
  | noptr-declarator parameters-and-qualifiers trailing-return-type

ptr-declarator ::=
    noptr-declarator
  | ptr-operator ptr-declarator

noptr-declarator ::=
    declarator-id attribute-specifier-seq?
  | noptr-declarator parameters-and-qualifiers
  | noptr-declarator "[" constant-expression? "]" attribute-specifier-seq?
  | "(" ptr-declarator ")"

parameters-and-qualifiers ::=
    "(" parameter-declaration-clause ")" cv-qualifier-seq?
        ref-qualifier? noexcept-specifier? attribute-specifier-seq?

trailing-return-type ::=
    "->" type-id

ptr-operator ::=
    "*" attribute-specifier-seq? cv-qualifier-seq?
  | "&" attribute-specifier-seq?
  | "&&" attribute-specifier-seq?
  | nested-name-specifier "*" attribute-specifier-seq? cv-qualifier-seq?

cv-qualifier-seq ::=
    cv-qualifier cv-qualifier-seq?

cv-qualifier ::=
    "const"
  | "volatile"

ref-qualifier ::=
    "&"
  | "&&"

declarator-id ::=
    "..."? id-expression

type-id ::=
    type-specifier-seq abstract-declarator?

defining-type-id ::=
    defining-type-specifier-seq abstract-declarator?

abstract-declarator ::=
    ptr-abstract-declarator
  | noptr-abstract-declarator? parameters-and-qualifiers trailing-return-type
  | abstract-pack-declarator

ptr-abstract-declarator ::=
    noptr-abstract-declarator
  | ptr-operator ptr-abstract-declarator?

noptr-abstract-declarator ::=
    noptr-abstract-declarator? parameters-and-qualifiers
  | noptr-abstract-declarator? "[" constant-expression? "]" attribute-specifier-seq?
  | "(" ptr-abstract-declarator ")"

abstract-pack-declarator ::=
    noptr-abstract-pack-declarator
  | ptr-operator abstract-pack-declarator

noptr-abstract-pack-declarator ::=
    noptr-abstract-pack-declarator parameters-and-qualifiers
  | "..."

parameter-declaration-clause ::=
    parameter-declaration-list? "..."?
  | parameter-declaration-list "," "..."

parameter-declaration-list ::=
    parameter-declaration
  | parameter-declaration-list "," parameter-declaration

parameter-declaration ::=
    attribute-specifier-seq? "this"? decl-specifier-seq declarator
  | attribute-specifier-seq? decl-specifier-seq declarator "=" initializer-clause
  | attribute-specifier-seq? "this"? decl-specifier-seq abstract-declarator?
  | attribute-specifier-seq? decl-specifier-seq abstract-declarator? "=" initializer-clause

initializer ::=
    brace-or-equal-initializer
  | "(" expression-list ")"

brace-or-equal-initializer ::=
    "=" initializer-clause
  | braced-init-list

initializer-clause ::=
    assignment-expression
  | braced-init-list

braced-init-list ::=
    "{" initializer-list ","? "}"
  | "{" designated-initializer-list ","? "}"
  | "{" "}"

initializer-list ::=
    initializer-clause "..."?
  | initializer-list "," initializer-clause "..."?

designated-initializer-list ::=
    designated-initializer-clause
  | designated-initializer-list "," designated-initializer-clause

designated-initializer-clause ::=
    designator brace-or-equal-initializer

designator ::=
    "." identifier

expr-or-braced-init-list ::=
    expression
  | braced-init-list

function-definition ::=
    attribute-specifier-seq? decl-specifier-seq? declarator virt-specifier-seq? function-body
  | attribute-specifier-seq? decl-specifier-seq? declarator requires-clause function-body

function-body ::=
    ctor-initializer? compound-statement
  | function-try-block
  | "=" "default" ";"
  | "=" "delete" ";"

enum-name ::=
    identifier

enum-specifier ::=
    enum-head "{" enumerator-list? "}"
  | enum-head "{" enumerator-list "," "}"

enum-head ::=
    enum-key attribute-specifier-seq? enum-head-name? enum-base?

enum-head-name ::=
    nested-name-specifier? identifier

opaque-enum-declaration ::=
    enum-key attribute-specifier-seq? enum-head-name enum-base? ";"

enum-key ::=
    "enum"
  | "enum" "class"
  | "enum" "struct"

enum-base ::=
    ":" type-specifier-seq

enumerator-list ::=
    enumerator-definition
  | enumerator-list "," enumerator-definition

enumerator-definition ::=
    enumerator
  | enumerator "=" constant-expression

enumerator ::=
    identifier attribute-specifier-seq?

using-enum-declaration ::=
    "using" "enum" using-enum-declarator ";"

using-enum-declarator ::=
    nested-name-specifier? identifier
  | nested-name-specifier? simple-template-id

namespace-name ::=
        identifier
  | namespace-alias

namespace-definition ::=
        named-namespace-definition
  | unnamed-namespace-definition
  | nested-namespace-definition

named-namespace-definition ::=
        "inline"? "namespace" attribute-specifier-seq? identifier "{" namespace-body "}"

unnamed-namespace-definition ::=
        "inline"? "namespace" attribute-specifier-seq? "{" namespace-body "}"

nested-namespace-definition ::=
        "namespace" enclosing-namespace-specifier "::" "inline"? identifier "{" namespace-body "}"

enclosing-namespace-specifier ::=
        identifier
  | enclosing-namespace-specifier "::" "inline"? identifier

namespace-body ::=
        declaration-seq?

namespace-alias ::=
        identifier

namespace-alias-definition ::=
        "namespace" identifier "=" qualified-namespace-specifier ";"

qualified-namespace-specifier ::=
    nested-name-specifier? namespace-name

using-directive ::=
    attribute-specifier-seq? "using" "namespace" nested-name-specifier? namespace-name ";"

using-declaration ::=
    "using" using-declarator-list ";"

using-declarator-list ::=
    using-declarator "..."?
  | using-declarator-list "," using-declarator "..."?

using-declarator ::=
    "typename"? nested-name-specifier unqualified-id

asm-declaration ::=
    attribute-specifier-seq? "asm" "(" balanced-token-seq ")" ";"

linkage-specification ::=
    "extern" unevaluated-string "{" declaration-seq? "}"
  | "extern" unevaluated-string name-declaration

attribute-specifier-seq ::=
  attribute-specifier-seq? attribute-specifier

attribute-specifier ::=
  "[" "[" attribute-using-prefix? attribute-list "]" "]"
  | alignment-specifier

alignment-specifier ::=
  "alignas" "(" type-id "..."? ")"
  | "alignas" "(" constant-expression "..."? ")"

attribute-using-prefix ::=
  "using" attribute-namespace ":"

attribute-list ::=
  attribute?
  | attribute-list "," attribute?
  | attribute "..."
  | attribute-list "," attribute "..."

attribute ::=
    attribute-token attribute-argument-clause?

attribute-token ::=
    identifier
  | attribute-scoped-token

attribute-scoped-token ::=
    attribute-namespace "::" identifier

attribute-namespace ::=
    identifier

attribute-argument-clause ::=
    "(" balanced-token-seq? ")"

balanced-token-seq ::=
    balanced-token
  | balanced-token-seq balanced-token

balanced-token ::=
    "(" balanced-token-seq? ")"
  | "[" balanced-token-seq? "]"
  | "{" balanced-token-seq? "}"
  | "{any token other than a parenthesis, a bracket, or a brace}"

//== modules.tex

module-declaration ::=
    "export"? "module" module-name module-partition? attribute-specifier-seq? ";"

module-name ::=
    module-name-qualifier? identifier

module-partition ::=
    ":" module-name-qualifier? identifier

module-name-qualifier ::=
    identifier "."
  | module-name-qualifier identifier "."

export-declaration ::=
    "export" name-declaration
  | "export" "{" declaration-seq? "}"
  | "export" module-import-declaration

module-import-declaration ::=
    "import" module-name attribute-specifier-seq? ";"
  | "import" module-partition attribute-specifier-seq? ";"
  | "import" header-name attribute-specifier-seq? ";"

global-module-fragment ::=
    "module" ";" declaration-seq?

private-module-fragment ::=
    "module" ":" "private" ";" declaration-seq?

//== classes.tex

class-name ::=
    identifier
  | simple-template-id

class-specifier ::=
    class-head "{" member-specification? "}"

class-head ::=
    class-key attribute-specifier-seq? class-head-name class-virt-specifier? base-clause?
  | class-key attribute-specifier-seq? base-clause?

class-head-name ::=
    nested-name-specifier? class-name

class-virt-specifier ::=
    "final"

class-key ::=
    "class"
  | "struct"
  | "union"

member-specification ::=
    member-declaration member-specification?
  | access-specifier ":" member-specification?

member-declaration ::=
    attribute-specifier-seq? decl-specifier-seq? member-declarator-list? ";"
  | function-definition
  | using-declaration
  | using-enum-declaration
  | static_assert-declaration
  | template-declaration
  | explicit-specialization
  | deduction-guide
  | alias-declaration
  | opaque-enum-declaration
  | empty-declaration

member-declarator-list ::=
    member-declarator
  | member-declarator-list "," member-declarator

member-declarator ::=
    declarator virt-specifier-seq? pure-specifier?
  | declarator requires-clause
  | declarator brace-or-equal-initializer?
  | identifier? attribute-specifier-seq? ":" constant-expression brace-or-equal-initializer?

virt-specifier-seq ::=
    virt-specifier
  | virt-specifier-seq virt-specifier

virt-specifier ::=
    "override"
  | "final"

pure-specifier ::=
    "=" "0"

conversion-function-id ::=
    "operator" conversion-type-id

conversion-type-id ::=
    type-specifier-seq conversion-declarator?

conversion-declarator ::=
    ptr-operator conversion-declarator?

base-clause ::=
    ":" base-specifier-list

base-specifier-list ::=
    base-specifier "..."?
  | base-specifier-list "," base-specifier "..."?

base-specifier ::=
    attribute-specifier-seq? class-or-decltype
  | attribute-specifier-seq? "virtual" access-specifier? class-or-decltype
  | attribute-specifier-seq? access-specifier "virtual"? class-or-decltype

class-or-decltype ::=
    nested-name-specifier? type-name
  | nested-name-specifier "template" simple-template-id
  | decltype-specifier

access-specifier ::=
    "private"
  | "protected"
  | "public"

ctor-initializer ::=
    ":" mem-initializer-list

mem-initializer-list ::=
    mem-initializer "..."?
  | mem-initializer-list "," mem-initializer "..."?

mem-initializer ::=
    mem-initializer-id "(" expression-list? ")"
  | mem-initializer-id braced-init-list

mem-initializer-id ::=
    class-or-decltype
  | identifier

//== overloading.tex

operator-function-id ::=
    "operator" operator

operator ::=
    "new" | "delete" | "new[]" | "delete[]" | "co_await" | "()" | "[]" | "->" | "->*"
  | "~" | "!" | "+" | "-" | "*" | "/" | "%" | "^" | "&"
  | "|" | "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "&="
  | "|=" | "==" | "!=" | "<" | ">" | "<=" | ">=" | "<=>" | "&&"
  | "||" | "<<" | ">>" | "<<=" | ">>=" | "++" | "--" | ","

literal-operator-id ::=
    "operator" unevaluated-string identifier
  | "operator" user-defined-string-literal

//== templates.tex

template-declaration ::=
  template-head declaration
  | template-head concept-definition

template-head ::=
  "template" "<" template-parameter-list ">" requires-clause?

template-parameter-list ::=
  template-parameter
  | template-parameter-list "," template-parameter

requires-clause ::=
  "requires" constraint-logical-or-expression

constraint-logical-or-expression ::=
  constraint-logical-and-expression
  | constraint-logical-or-expression "||" constraint-logical-and-expression

constraint-logical-and-expression ::=
  primary-expression
  | constraint-logical-and-expression "&&" primary-expression

template-parameter ::=
  type-parameter
  | parameter-declaration

type-parameter ::=
  type-parameter-key "..."? identifier?
  | type-parameter-key identifier? "=" type-id
  | type-constraint "..."? identifier?
  | type-constraint identifier? "=" type-id
  | template-head type-parameter-key "..."? identifier?
  | template-head type-parameter-key identifier? "=" id-expression

type-parameter-key ::=
  "class"
  | "typename"

type-constraint ::=
  nested-name-specifier? concept-name
  | nested-name-specifier? concept-name "<" template-argument-list? ">"

simple-template-id ::=
  template-name "<" template-argument-list? ">"

template-id ::=
  simple-template-id
  | operator-function-id "<" template-argument-list? ">"
  | literal-operator-id "<" template-argument-list? ">"

template-name ::=
  identifier

template-argument-list ::=
  template-argument "..."?
  | template-argument-list "," template-argument "..."?

template-argument ::=
  constant-expression
  | type-id
  | id-expression
  | braced-init-list

constraint-expression ::=
    logical-or-expression

deduction-guide ::=
    explicit-specifier? template-name "(" parameter-declaration-clause ")" "->" simple-template-id ";"

concept-definition ::=
  "concept" concept-name attribute-specifier-seq? "=" constraint-expression ";"

concept-name ::=
  identifier

typename-specifier ::=
  "typename" nested-name-specifier identifier
  | "typename" nested-name-specifier "template"? simple-template-id

explicit-instantiation ::=
  "extern"? "template" declaration

explicit-specialization ::=
  "template" "<" ">" declaration

//== exceptions.tex

try-block ::=
    "try" compound-statement handler-seq

function-try-block ::=
    "try" ctor-initializer? compound-statement handler-seq

handler-seq ::=
    handler handler-seq?

handler ::=
    "catch" "(" exception-declaration ")" compound-statement

exception-declaration ::=
    attribute-specifier-seq? type-specifier-seq declarator
  | attribute-specifier-seq? type-specifier-seq abstract-declarator?
  | "..."

noexcept-specifier ::=
    "noexcept" "(" constant-expression ")"
  | "noexcept"

//== preprocessor.tex

preprocessing-file ::=
    group?
  | module-file

module-file ::=
    pp-global-module-fragment? pp-module group? pp-private-module-fragment?

pp-global-module-fragment ::=
    "module" ";" new-line group?

pp-private-module-fragment ::=
    "module" ":" "private" ";" new-line group?

group ::=
    group-part
  | group group-part

group-part ::=
    control-line
  | if-section
  | text-line
  | "#" conditionally-supported-directive

control-line ::=
    "#" "include" pp-tokens new-line
  | pp-import
  | "#" "define" identifier replacement-list new-line
  | "#" "define" identifier lparen identifier-list? ")" replacement-list new-line
  | "#" "define" identifier lparen "..." ")" replacement-list new-line
  | "#" "define" identifier lparen identifier-list "," "..." ")" replacement-list new-line
  | "#" "undef" identifier new-line
  | "#" "line" pp-tokens new-line
  | "#" "error" pp-tokens? new-line
  | "#" "warning" pp-tokens? new-line
  | "#" "pragma" pp-tokens? new-line
  | "#" new-line

if-section ::=
    if-group elif-groups? else-group? endif-line

if-group ::=
    "#" "if" constant-expression new-line group?
  | "#" "ifdef" identifier new-line group?
  | "#" "ifndef" identifier new-line group?

elif-groups ::=
    elif-group
  | elif-groups elif-group

elif-group ::=
    "#" "elif" constant-expression new-line group?
  | "#" "elifdef" identifier new-line group?
  | "#" "elifndef" identifier new-line group?

else-group ::=
    "#" "else" new-line group?

endif-line ::=
    "#" "endif" new-line

text-line ::=
    pp-tokens? new-line

conditionally-supported-directive ::=
    pp-tokens new-line

lparen ::=
    '{a "(" character not immediately preceded by whitespace}'

identifier-list ::=
    identifier
  | identifier-list "," identifier

replacement-list ::=
    pp-tokens?

pp-tokens ::=
    preprocessing-token
  | pp-tokens preprocessing-token

new-line ::=
    "{the new-line character}"

defined-macro-expression ::=
    "defined" identifier
  | "defined" "(" identifier ")"

h-preprocessing-token ::=
    '{any preprocessing-token other than ">"}'

h-pp-tokens ::=
    h-preprocessing-token
  | h-pp-tokens h-preprocessing-token

header-name-tokens ::=
    string-literal
  | "<" h-pp-tokens ">"

has-include-expression ::=
    "has_include" "(" header-name ")"
  | "has_include" "(" header-name-tokens ")"

has-attribute-expression ::=
    "has_cpp_attribute" "(" pp-tokens ")"

pp-module ::=
    "export"? "module" pp-tokens? ";" new-line

pp-import ::=
    "export"? "import" header-name pp-tokens? ";" new-line
  | "export"? "import" header-name-tokens pp-tokens? ";" new-line
  | "export"? "import" pp-tokens ";" new-line

va-opt-replacement ::=
    "VA_OPT" "(" pp-tokens? ")"

Carbon "using Nonnull = T _Nonnull;"

While testing cxx with carbon explorer sources I found this file (carbon-lang/explorer/base/nonnull.h) that fail to parse:

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef CARBON_EXPLORER_BASE_NONNULL_H_
#define CARBON_EXPLORER_BASE_NONNULL_H_

#include <type_traits>

namespace Carbon {

// A non-nullable pointer. Written as `Nonnull<T*>` instead of `T*`.
//
// Sanitizers enforce this dynamically on assignment, return, and when passing
// as an argument. Static analysis will also track erroneous uses of `nullptr`.
template <typename T,
          typename std::enable_if_t<std::is_pointer_v<T>>* = nullptr>
using Nonnull = T _Nonnull;

}  // namespace Carbon

#endif  // CARBON_EXPLORER_BASE_NONNULL_H_

Test:

cxx test-carbon-nonull.cpp
test-carbon-nonull.cpp:18:19: expected ';'
using Nonnull = T _Nonnull;
                  ^
test-carbon-nonull.cpp:18:27: expected a declaration
using Nonnull = T _Nonnull;
                          ^

Can't parse sizeof properly

While testing "cxx" with Lua-5.4.6 code I found this problem:

#define dumpVector(D,v,n)	dumpBlock(D,v,(n)*sizeof((v)[0]))

static void dumpBlock (const char *D, const void *b, unsigned int size) {
}

static void dumpString (const char *D, const char *str) {
    unsigned int size = 0;
    dumpVector(D, str, size);
}
g++ -fsyntax-only -x c++ test-macro-sizeof.cpp
>Exit code: 0

clang++ -fsyntax-only -x c++ test-macro-sizeof.cpp
>Exit code: 0

./cxx test-macro-sizeof.cpp
test-macro-sizeof.cpp:1:57: expected ';'
#define dumpVector(D,v,n)	dumpBlock(D,v,(n)*sizeof((v)[0]))
                         	                              ^
Command exited with non-zero status 1

./cxx -E test-macro-sizeof.cpp
# 3 "test-macro-sizeof.cpp"
static void dumpBlock (const char *D, const void *b, unsigned int size) {
}
# 6 "test-macro-sizeof.cpp"
static void dumpString (const char *D, const char *str) {
unsigned int size = 0;
# 1 "test-macro-sizeof.cpp"
dumpBlock(D, str,( size)*sizeof(( str)[0]));
# 9 "test-macro-sizeof.cpp"
}

cxx can't handle string concatenation in macros correctly

See the sample bellow and the output for cxx and g++:

#define TO_OSTREAM_EMPTY(stream_type, strpfx) \
        static void empty(std::stream_type& stream_, bool asEbnfRR = false) \
        {\
            if(asEbnfRR) stream_ << strpfx##"/*%empty*/";\
            else stream_ << strpfx##"%empty";\
        }

        TO_OSTREAM_EMPTY(ostream, )
        TO_OSTREAM_EMPTY(wostream, L)
        TO_OSTREAM_EMPTY(basic_ostream<char32_t>, U)

Output:

g++ -E test-macro.cpp
# 1 "test-macro.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test-macro.cpp"
        static void empty(std::ostream& stream_, bool asEbnfRR = false) { if(asEbnfRR) stream_ << "/*%empty*/"; else stream_ << "%empty"; }
        static void empty(std::wostream& stream_, bool asEbnfRR = false) { if(asEbnfRR) stream_ << L"/*%empty*/"; else stream_ << L"%empty"; }
        static void empty(std::basic_ostream<char32_t>& stream_, bool asEbnfRR = false) { if(asEbnfRR) stream_ << U"/*%empty*/"; else stream_ << U"%empty"; }
./cxx -E test-macro.cpp
# 2 "test-macro.cpp"
static void empty(std::ostream& stream_, bool asEbnfRR = false) { if(asEbnfRR) stream_ <<; else stream_ <<; }
# 2 "test-macro.cpp"
static void empty(std::wostream& stream_, bool asEbnfRR = false) { if(asEbnfRR) stream_ << L"/*%empty*/"; else stream_ << L"%empty"; }
# 2 "test-macro.cpp"
static void empty(std::basic_ostream<char32_t>& stream_, bool asEbnfRR = false) { if(asEbnfRR) stream_ << U"/*%empty*/"; else stream_ << U"%empty"; }

Question regarding preprocessor directives

Hello,

I am thinking about using cplusplus to write some personal source analysis and transformation tools. The first one i want to implement is a simple file dependency analyzer.

Is this possible? At first glance it doesn't appear that the include directives are preserved. Am i missing something?

For me the value of your project is in a lighter libclang (like about 50 tones lighter) for analysis purposes.

Can't parse "va_arg"

While testing this project with this sample:

#include <stdio.h>
#include <stdarg.h>
#include <math.h>

double stddev(int count, ...)
{
    double sum = 0;
    double sum_sq = 0;
    va_list args;
    va_start(args, count);
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args, double);
        sum += num;
        sum_sq += num*num;
    }
    va_end(args);
    return sqrt(sum_sq/count - (sum/count)*(sum/count));
}

int main(void)
{
    printf("%f\n", stddev(4, 25.0, 27.3, 26.9, 25.7));
}

I'm getting this error message:

./cxx valist.cpp
valist.cpp:12:9: expected a statement
        double num = va_arg(args, double);
        ^

Add "-M" and "-MM" command line options

To help debug I propose to add -M and -MM command line options, I already got an MVP partially working (it's missing extract the filename without path and extension to use as root dependency like src/test.cpp -> test.o and check the last entry in the loop to omit the line continuation), see bellow .

Or maybe drop the line continuation and root dependency and simple dump the filenames.

--------------------------- src/frontend/cxx/cli.cc ---------------------------
index a2f9aa8..795cd68 100644
@@ -132,6 +132,12 @@ std::vector<CLIOptionDescr> options{
     {"-dM", "Print macro definitions in -E mode instead of normal output",
      &CLI::opt_dM},
 
+    {"-M", "Print dependencies of the main source file",
+     &CLI::opt_M},
+
+    {"-MM", "Print dependencies of the main source file, excluding system path",
+     &CLI::opt_MM},
+
     {"-S", "Only run preprocess and compilation steps", &CLI::opt_S,
      CLIOptionVisibility::kExperimental},
 

---------------------------- src/frontend/cxx/cli.h ----------------------------
index 6c7d61e..9c7ec57 100644
@@ -54,6 +54,8 @@ class CLI {
   bool opt_ast_dump = false;
   bool opt_ir_dump = false;
   bool opt_dM = false;
+  bool opt_MM = false;
+  bool opt_M = false;
   bool opt_dump_symbols = false;
   bool opt_dump_tokens = false;
   bool opt_E = false;

------------------------- src/frontend/cxx/frontend.cc -------------------------
index 2197050..d51809b 100644
@@ -238,7 +238,7 @@ auto runOnFile(const CLI& cli, const std::string& fileName) -> bool {
   }
 
   if (auto source = readAll(fileName)) {
-    if (cli.opt_E && !cli.opt_dM) {
+    if (cli.opt_E && !(cli.opt_dM || cli.opt_M || cli.opt_MM)) {
       preprocesor->preprocess(std::move(*source), fileName, output);
       shouldExit = true;
     } else {
@@ -247,6 +247,12 @@ auto runOnFile(const CLI& cli, const std::string& fileName) -> bool {
       if (cli.opt_dM) {
         preprocesor->printMacros(output);
         shouldExit = true;
+      } else if (cli.opt_M) {
+        preprocesor->printDependencies(output, false);
+        shouldExit = true;
+      } else if (cli.opt_MM) {
+        preprocesor->printDependencies(output, true);
+        shouldExit = true;
       } else if (cli.opt_dump_tokens) {
         dumpTokens(cli, unit, output);
         shouldExit = true;

------------------------ src/parser/cxx/preprocessor.cc ------------------------
index 7fc45d0..dbc26d3 100644
@@ -556,6 +556,7 @@ struct Preprocessor::Private {
     if (sourceFiles_.size() >= 4096) {
       cxx_runtime_error("too many source files");
     }
+    //std::cout << "createSourceFile: " << fileName << std::endl;
 
     const int sourceFileId = static_cast<int>(sourceFiles_.size() + 1);
 
@@ -2262,6 +2263,22 @@ void Preprocessor::printMacros(std::ostream &out) const {
   }
 }
 
+void Preprocessor::printDependencies(std::ostream &out, bool noSysPath) const {
+  for (const auto &sourceFile : d->sourceFiles_) {
+    if (noSysPath) {
+      bool isSysPath = false; 
+      for (const auto &sysPath : d->systemIncludePaths_) {
+        if (sourceFile->fileName.find(sysPath) == 0) {
+          isSysPath = true;
+          break;
+        }
+      }
+      if (isSysPath) continue;
+    }
+    out << cxx::format(" {} \\\n", sourceFile->fileName);
+  }
+}
+
 void Preprocessor::getTokenStartPosition(const Token &token, unsigned *line,
                                          unsigned *column,
                                          std::string_view *fileName) const {

------------------------ src/parser/cxx/preprocessor.h ------------------------
index 5585be5..89938a0 100644
@@ -97,6 +97,8 @@ class Preprocessor {
 
   void printMacros(std::ostream &out) const;
 
+  void printDependencies(std::ostream &out, bool noSysPath) const;
+
   void getTokenStartPosition(const Token &token, unsigned *line,
                              unsigned *column,
                              std::string_view *fileName) const;

Bad preprocessing behavior

While test to parse sqlite3.c I found a bad preprocessor behavior, see bellow.

test-bug-sqlite3.c:

static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
  int rc = SQLITE_OK;
  IncrMerger *pIncr = pReadr->pIncr;
  SortSubtask *pTask = pIncr->pTask;
  sqlite3 *db = pTask->pSorter->db;

  /* eMode is always INCRINIT_NORMAL in single-threaded mode */
  assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );

  rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);

  /* Set up the required files for pIncr. A multi-threaded IncrMerge object
  ** requires two temp files to itself, whereas a single-threaded object
  ** only requires a region of pTask->file2. */
  if( rc==SQLITE_OK ){
    int mxSz = pIncr->mxSz;
#if SQLITE_MAX_WORKER_THREADS>0
    if( pIncr->bUseThread ){
      rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd);
      if( rc==SQLITE_OK ){
        rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd);
      }
    }else
#endif
    /*if( !pIncr->bUseThread )*/{
      if( pTask->file2.pFd==0 ){
        assert( pTask->file2.iEof>0 );
        rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd);
        pTask->file2.iEof = 0;
      }
      if( rc==SQLITE_OK ){
        pIncr->aFile[1].pFd = pTask->file2.pFd;
        pIncr->iStartOff = pTask->file2.iEof;
        pTask->file2.iEof += mxSz;
      }
    }
  }

#if SQLITE_MAX_WORKER_THREADS>0
  if( rc==SQLITE_OK && pIncr->bUseThread ){
    /* Use the current thread to populate aFile[1], even though this
    ** PmaReader is multi-threaded. If this is an INCRINIT_TASK object,
    ** then this function is already running in background thread
    ** pIncr->pTask->thread.
    **
    ** If this is the INCRINIT_ROOT object, then it is running in the
    ** main VDBE thread. But that is Ok, as that thread cannot return
    ** control to the VDBE or proceed with anything useful until the
    ** first results are ready from this merger object anyway.
    */
    assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK );
    rc = vdbeIncrPopulate(pIncr);
  }
#endif

  if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){
    rc = vdbePmaReaderNext(pReadr);
  }

  return rc;
}
./cxx -E test-bug-sqlite3.c
# 1 "test-bug-sqlite3.c"
static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
int rc = SQLITE_OK;
IncrMerger *pIncr = pReadr->pIncr;
SortSubtask *pTask = pIncr->pTask;
sqlite3 *db = pTask->pSorter->db;
# 8 "test-bug-sqlite3.c"
assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );
# 10 "test-bug-sqlite3.c"
rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
# 15 "test-bug-sqlite3.c"
if( rc==SQLITE_OK ){
int mxSz = pIncr->mxSz;
# 26 "test-bug-sqlite3.c"
if( pTask->file2.pFd==0 ){
assert( pTask->file2.iEof>0 );
rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd);
pTask->file2.iEof = 0;
}
if( rc==SQLITE_OK ){
pIncr->aFile[1].pFd = pTask->file2.pFd;
pIncr->iStartOff = pTask->file2.iEof;
pTask->file2.iEof += mxSz;
}
}
}  ////!!!!!<<<<< notice that cxx closes the function block here !!!!!!<<<<<<<<<<
# 56 "test-bug-sqlite3.c"
if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){
rc = vdbePmaReaderNext(pReadr);
}
# 60 "test-bug-sqlite3.c"
return rc;
}
g++ -E test-bug-sqlite3.c
# 1 "test-bug-sqlite3.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test-bug-sqlite3.c"
static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
  int rc = SQLITE_OK;
  IncrMerger *pIncr = pReadr->pIncr;
  SortSubtask *pTask = pIncr->pTask;
  sqlite3 *db = pTask->pSorter->db;


  assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );

  rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);




  if( rc==SQLITE_OK ){
    int mxSz = pIncr->mxSz;
# 25 "test-bug-sqlite3.c"
                                {
      if( pTask->file2.pFd==0 ){
        assert( pTask->file2.iEof>0 );
        rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd);
        pTask->file2.iEof = 0;
      }
      if( rc==SQLITE_OK ){
        pIncr->aFile[1].pFd = pTask->file2.pFd;
        pIncr->iStartOff = pTask->file2.iEof;
        pTask->file2.iEof += mxSz;
      }
    }
  }
# 56 "test-bug-sqlite3.c"
  if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){
    rc = vdbePmaReaderNext(pReadr);
  }

  return rc;
}

What is the final purpose of this parser

I know this project started several years ago, and after that, it just halted for several years. And I see you have resumed the develop again in recent months. First, I'd like to say, good work!

Now, here comes my question, what does the final purpose of this parser. Will it support some features like Clang, for example, code completion, find declaration or find implementation.

If I remember correctly, you are the original author of the parser in QTCreator/Kdevelope, but now those IDEs all switches to use Clang based parser.

Thanks.

Memory usage and permissive parsing with sqlite3

Trying to parse sqlite3.c with this project I found that it can parse it without showing any error/warnings but uses a bit more memory than gcc/g++ (cxx=3,000,000 allocations, g++=500,000 allocations):

/usr/bin/time ./cxx -toolchain linux ./sqlite3.cpp -fsyntax-only -I.
1.01user 0.06system 0:01.08elapsed 99%CPU (0avgtext+0avgdata 146628maxresident)k
0inputs+0outputs (0major+39686minor)pagefaults 0swaps
/usr/bin/time g++ -fpermissive ./sqlite3.cpp -fsyntax-only -I.
1.08user 0.07system 0:01.16elapsed 99%CPU (0avgtext+0avgdata 115564maxresident)k
0inputs+0outputs (0major+29614minor)pagefaults 0swaps
/usr/bin/time myvalgrind ./cxx -toolchain linux ./sqlite3.cpp -fsyntax-only -I.
==21479==     in use at exit: 0 bytes in 0 blocks
==21479==   total heap usage: 3,003,109 allocs, 3,003,109 frees, 4,175,102,281 bytes allocated
55.95user 0.31system 0:56.27elapsed 99%CPU (0avgtext+0avgdata 408920maxresident)k
0inputs+0outputs (0major+127697minor)pagefaults 0swaps
/usr/bin/time myvalgrind --trace-children=yes g++ -fpermissive ./sqlite3.cpp -fsyntax-only -I.
==21623== Command: g++ -fpermissive ./sqlite3.cpp -fsyntax-only -I.
==21624==     in use at exit: 7,045,865 bytes in 15,051 blocks
==21624==   total heap usage: 490,444 allocs, 475,393 frees, 649,209,160 bytes allocated
==21624== Command: /usr/lib/gcc/x86_64-linux-gnu/9/cc1plus -quiet -I . -imultiarch x86_64-linux-gnu -D_GNU_SOURCE ./sqlite3.cpp -quiet -dumpbase sqlite3.cpp -mtune=generic -march=x86-64 -auxbase sqlite3 -fpermissive -fsyntax-only -o /dev/null -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security
==21623==     in use at exit: 189,449 bytes in 69 blocks
==21623==   total heap usage: 234 allocs, 165 frees, 215,031 bytes allocated
40.27user 0.34system 0:40.63elapsed 99%CPU (0avgtext+0avgdata 337688maxresident)k
4416inputs+0outputs (1major+147633minor)pagefaults 0swaps

But renaming sqlite3.c to sqlite3.cpp and fixing several errors pointed out by g++ then this project still doesn't show any warning/error while g++ needs -fpermissive to parse it and show several warnings:

./sqlite3.cpp: In function ‘void* sqlite3MemMalloc(int)’:
./sqlite3.cpp:26707:44: warning: invalid conversion from ‘void*’ to ‘sqlite3_int64*’ {aka ‘long long int*’} [-fpermissive]
26707 | #define SQLITE_MALLOC(x)             malloc(x)
      |                                      ~~~~~~^~~
      |                                            |
      |                                            void*
./sqlite3.cpp:26773:7: note: in expansion of macro ‘SQLITE_MALLOC’
26773 |   p = SQLITE_MALLOC( nByte+8 );
      |       ^~~~~~~~~~~~~
./sqlite3.cpp: In function ‘void* sqlite3MemRealloc(void*, int)’:
./sqlite3.cpp:26709:45: warning: invalid conversion from ‘void*’ to ‘sqlite3_int64*’ {aka ‘long long int*’} [-fpermissive]
26709 | #define SQLITE_REALLOC(x,y)          realloc((x),(y))
      |                                      ~~~~~~~^~~~~~~~~
      |                                             |
      |                                             void*
...
./sqlite3.cpp: In function ‘int jsonEachNext(sqlite3_vtab_cursor*)’:
./sqlite3.cpp:209852:32: warning: invalid conversion from ‘void*’ to ‘JsonParent*’ [-fpermissive]
209852 |         pNew = sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew);
       |                ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       |                                |
       |                                void*
./sqlite3.cpp: In function ‘int jsonEachFilter(sqlite3_vtab_cursor*, int, const char*, int, sqlite3_value**)’:
./sqlite3.cpp:210179:37: warning: invalid conversion from ‘void*’ to ‘JsonParent*’ [-fpermissive]
210179 |     p->aParent = sqlite3DbMallocZero(p->db, sizeof(JsonParent));
       |                  ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
       |                                     |
       |                                     void*

I'm attaching the files used by this test:
sqlite3-c-cpp.zip

Testing with https://github.com/duneroadrunner/SaferCPlusPlus

While testing cxx with https://github.com/duneroadrunner/SaferCPlusPlus we I'm getting this errors (while g++-9.4 parse it fine):

cxx SaferCPlusPlus/examples/msetl_example/msetl_example.cpp -fsyntax-only -toolchain linux -ISaferCPlusPlus/examples/msetl_example/../../include
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:69: expected ')'
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:126: expected a declarator
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:132: expected a declarator
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                               ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:133: expected a declaration
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:136: expected a declarator
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                   ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:137: expected a declaration
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                    ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:141: expected a declarator
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                        ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:142: expected a declaration
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:143: expected a declaration
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                          ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:160: expected a declarator
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                                           ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:161: expected a declaration
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                                            ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:162: expected a declaration
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                                             ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:164: expected a declaration
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                                               ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1326:193: expected a declaration
				gnii_vector(_Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) { /*m_debug_size = size();*/ }
				                                                                                                                                                                                            ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:5: expected ';'
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:75: expected ')'
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:132: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                               ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:138: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                     ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:139: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:142: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:143: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                          ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:147: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                              ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:148: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                               ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:149: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                                ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:166: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                                                 ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:167: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                                                  ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:168: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                                                   ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1327:170: expected a declaration
				gnii_vector(const _Myt& _X) : base_class(CNoopOrReadLockedSrcRefHolder<typename std::is_trivially_copy_constructible<_Ty>::type, _Myt>(_X).ref().contained_vector()) {
				                                                                                                                                                                     ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1347:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1348:28: expected ';'
					structure_change_guard<decltype(_X.m_structure_change_mutex)> lock(_X.m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1354:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1355:39: expected ';'
					noop_or_structure_no_change_guard<typename mse::impl::conjunction<std::is_trivially_copy_constructible<_Ty>, std::is_trivially_move_constructible<_Ty>, std::is_trivially_destructible<_Ty> >::type, decltype(_X.m_structure_change_mutex)> lock(_X.m_structure_change_mutex);
					                                 ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1361:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1368:39: expected ';'
					noop_or_structure_no_change_guard<typename mse::impl::conjunction<std::is_trivially_copy_constructible<_Ty>, std::is_trivially_move_constructible<_Ty>, std::is_trivially_destructible<_Ty> >::type, decltype(_X.m_structure_change_mutex)> lock(_X.m_structure_change_mutex);
					                                 ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1386:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1394:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1398:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1424:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1428:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1432:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1437:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1444:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1449:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1489:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1494:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1500:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1504:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1509:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1586:4: expected a declaration
			private:
			^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1586:11: expected a declaration
			private:
			       ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1795:4: expected a declaration
			public:
			^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:1795:10: expected a declaration
			public:
			      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2105:31: expected ';'
					structure_no_change_guard<decltype(_Right.m_structure_change_mutex)> lock1(_Right.m_structure_change_mutex);
					                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2106:31: expected ';'
					structure_no_change_guard<decltype(m_structure_change_mutex)> lock2(m_structure_change_mutex);
					                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2114:31: expected ';'
					structure_no_change_guard<decltype(_Right.m_structure_change_mutex)> lock1(_Right.m_structure_change_mutex);
					                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2115:31: expected ';'
					structure_no_change_guard<decltype(m_structure_change_mutex)> lock2(m_structure_change_mutex);
					                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2120:31: expected ';'
					structure_no_change_guard<decltype(_Right.m_structure_change_mutex)> lock1(_Right.m_structure_change_mutex);
					                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2121:31: expected ';'
					structure_no_change_guard<decltype(m_structure_change_mutex)> lock2(m_structure_change_mutex);
					                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2129:31: expected ';'
					structure_no_change_guard<decltype(_Right.m_structure_change_mutex)> lock1(_Right.m_structure_change_mutex);
					                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2130:31: expected ';'
					structure_no_change_guard<decltype(m_structure_change_mutex)> lock2(m_structure_change_mutex);
					                         ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2162:4: expected a declaration
			private:
			^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2162:11: expected a declaration
			private:
			       ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2191:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2197:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2207:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2215:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2221:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2227:28: expected ';'
					structure_change_guard<decltype(m_structure_change_mutex)> lock1(m_structure_change_mutex);
					                      ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2304:51: expected a declaration
				friend /*class */xscope_ss_const_iterator_type;
				                                              ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2305:45: expected a declaration
				friend /*class */xscope_ss_iterator_type;
				                                        ^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2371:2: expected a declaration
	}
	^
SaferCPlusPlus/examples/msetl_example/../../include/msemsevector.h:2466:1: expected a declaration
}
^

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.