blob: 2f672ea896a575646b42a42d2c0ccf55b04dfa43 [file] [log] [blame]
//===-- macro-parser.h - parser helper for godumpspec ---------------------===//
//
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
//===----------------------------------------------------------------------===//
//
// Declaration MacroParser class.
//
//===----------------------------------------------------------------------===//
#ifndef MACRO_PARSER_H
#define MACRO_PARSER_H
#include <assert.h>
#include <string>
#include <unordered_set>
#include "macro-tokenizer.h"
#include "llvm/Support/raw_ostream.h"
// Stores the state of a given macro def; used during post-processing
// to detect cycles and to record the final disposition of a macro.
typedef enum {
Unvisited,
VisitInProgress,
VisitedWithError,
VisitedEmpty,
VisitedOK
} MacVisitState;
// Container for a macro definition.
struct MacroDef {
MacroDef() : mstate(Unvisited) { }
explicit MacroDef(const std::string &n) : name(n), mstate(Unvisited) {}
std::string name;
std::string body;
std::string expanded; // filled in during post-processing
MacVisitState mstate;
bool enumDef; // pseudo-macro created from enum literal
};
// Helper class to parse and post-process a collection of macros,
// notably the output of a "cc -E -dM <file>.c" compile. Expected use
// is that the client will invoke 'visitMacroLine' for each line read
// from a ""cc -E -dM" dump, then invoke 'postProcessMacros' and
// finally "emitMacros", which will emit equivalent Go constants for
// the macros.
//
// Since we're only interested in macros that can be translated into
// Go constants, the parser ignores function macros (ex: "#define foo(x) x+1")
// and other more elaborate/complex macro constructs. Macros with cycles
// are detected and not emitted, similarly macros containing references
// to other non-macro things (function calls, variables, etc).
//
// Macros are allowed to refer to enum literals, since this is a common
// usage in C; this is handled by allowing the client to pre-populate
// the macro table with definitions corresponding to enum literals.
class MacroParser {
public:
MacroParser() { }
int visitMacroLine(const std::string &line, unsigned lno);
void addEnumLiteralPseudoMacro(const std::string &name,
const std::string &value);
void postProcessMacros();
// Emit Go versions of the macros parsed so far to output stream
// "os". If a macro happens to have the same name as a previously
// emitted Go type (specified in 'emittedTypeNames') then do not
// emit that macro definition (types are given precedence over
// macros here).
void emitMacros(llvm::raw_ostream &os,
const std::unordered_set<std::string> &emittedTypeNames);
private:
void visitMacro(MacroDef *m);
MacroDef *lookup(const std::string &name) {
MacroDef t(name);
auto it = macros_.find(t);
if (it != macros_.end())
return const_cast<MacroDef*>(&(*it));
return nullptr;
}
class mdef_hash {
public:
unsigned int operator()(const MacroDef &d) const {
return std::hash<std::string>{}(d.name);
}
};
class mdef_equal {
public:
bool operator()(const MacroDef &d1, const MacroDef &d2) const {
return d1.name.compare(d2.name) == 0;
}
};
private:
std::unordered_set<MacroDef, mdef_hash, mdef_equal> macros_;
};
#endif // MACRO_PARSER_H