首页 > 技术文章 > nlohmann 非侵入式代码生成(llvm-cppparser)

sevencatwang 2022-03-25 10:21 原文

nlohmann是一个用起来很方便的json c++ 库,但是还得自己写一堆代码。特别是如果原来的结构较多,得改一堆,

可以用llvm cpp parser来生成这样的代码。

主函数

static void Main(string[] args)
{

var p = @"J:\fy\inc\";
var files = new List<string>()
{
"test.h"
};
var fullfns = files.Select(x => p + x).ToList();
ParseSourceFile(fullfns);


}

具体的代码如下:

public static bool ParseSourceFile(List<string> files)
{
// Lets setup the options for parsing the file.
var parserOptions = new ParserOptions
{
LanguageVersion = LanguageVersion.CPP17,
Verbose = true
};

parserOptions.Setup();

var parserResult = ClangParser.ParseSourceFiles(files, parserOptions);

if (parserResult.Kind != ParserResultKind.Success)
{
if (parserResult.Kind == ParserResultKind.FileNotFound)
Console.Error.WriteLine("some file was not found.");

for (uint i = 0; i < parserResult.DiagnosticsCount; i++)
{
var diag = parserResult.GetDiagnostics(i);

Console.WriteLine("{0}({1},{2}): {3}: {4}",
diag.FileName, diag.LineNumber, diag.ColumnNumber,
diag.Level.ToString().ToLower(), diag.Message);
}

parserResult.Dispose();
return false;
}

var astContext = ClangParser.ConvertASTContext(parserOptions.ASTContext);
parserResult.Dispose();

foreach (var unit in astContext.TranslationUnits)
{
if (unit.IsSystemHeader)
continue;
foreach (var ns in unit.Namespaces)
{
HandleNamespace(ns, ns.LogicalName);
}
}
return true;
}

 

public static void HandleClass(Class cls, string nsname)
{
if (!nsname.StartsWith("fy::"))
{
Console.WriteLine("not fy msg:"+nsname+"::"+cls.Name);
return;
}
var rosns = nsname.Substring(4);
StringBuilder sb_fromros = new StringBuilder();
sb_fromros.AppendLine("template<>");
sb_fromros.AppendFormat("FYMSG_DECL void copy_from_ros({0}::{1} &lhs, const {2}::{1} &rhs)", nsname, cls.Name,
rosns);
sb_fromros.AppendLine("{");
foreach (var mem in cls.Fields)
{
var fldname = mem.Name;
sb_fromros.AppendFormat(" copy_from_ros(lhs.{0}, rhs.{0});\n", fldname);
}

sb_fromros.AppendLine("}");


StringBuilder sb_tojson = new StringBuilder();
sb_tojson.AppendLine("template<>");
sb_tojson.Append(
$"FYMSG_DECL void to_json(nlohmann::json &js, const {nsname}::{cls.Name} &t)\n");
sb_tojson.AppendLine("{");
foreach (var mem in cls.Fields)
{
var fldname = mem.Name;
sb_tojson.AppendFormat(" to_json(js[\"{0}\"], t.{0});\n", fldname);
}

sb_tojson.AppendLine("}");

StringBuilder sb_fromjson = new StringBuilder();
sb_fromjson.AppendLine("template<>");
sb_fromjson.Append(
$"FYMSG_DECL void from_json(const nlohmann::json &js, {nsname}::{cls.Name} &t)\n");
sb_fromjson.AppendLine("{");
foreach (var mem in cls.Fields)
{
var fldname = mem.Name;
sb_fromjson.AppendFormat(" from_json(js[\"{0}\"], t.{0});\n", fldname);
}

sb_fromjson.AppendLine("}");

Console.WriteLine(sb_fromros.ToString());
Console.WriteLine();
Console.WriteLine(sb_tojson.ToString());
Console.WriteLine();
Console.WriteLine(sb_fromjson.ToString());
}

public static void HandleNamespace(Namespace ns, string fullns)
{
var clses = ns.Classes;
foreach (var cls in clses)
HandleClass(cls, fullns);
foreach (var subns in ns.Namespaces)
{
string newfullns = fullns + "::" + subns.LogicalName;
HandleNamespace(subns, newfullns);
}
}

 

 

如果序列化不是用的这个,同理可以在里面处理,其实就是通过cpp parser 拉到他的所有field,然后生成对应的代码。

推荐阅读