add new hc-gen implement

Signed-off-by: yuanbo <yuanbo@huawei.com>
This commit is contained in:
yuanbo
2021-06-02 14:39:47 +08:00
parent 6c6df99e10
commit e8873124c1
243 changed files with 11554 additions and 74 deletions
+24
View File
@@ -0,0 +1,24 @@
project(hc-gen)
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "-Wall")
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
add_definitions(-D OS_LINUX)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
add_definitions(-D OS_WIN)
add_definitions(-D MINGW32)
endif (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -s")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
if(CMAKE_BUILD_TYPE MATCHES Asan)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address")
endif()
aux_source_directory(src SOURCES)
add_executable(hc-gen ${SOURCES})
+12 -74
View File
@@ -1,84 +1,22 @@
# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
#
# HDF is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
# See the LICENSE file in the root of this repository for complete details.
TARGET := hc-gen
YACC_LEX_PREFIX :=HcsCompiler
C_FLAGS := -std=gnu99 -Wall -Werror -Wno-attributes -Wall
CC := gcc
YACC := bison
LEX := flex
Q = @
BUILD_DIR := build
TARGET := hc-gen
BOUNDS_CHECK_LIB := $(abspath ../../../../third_party/bounds_checking_function/)
INCLUDE_DIR := ./include $(BOUNDS_CHECK_LIB)/include
OUT_DIR := build
TEST_CASE := $(abspath ../../../adapter/lite/khdf/test/tools/hc-gen/test/unittest)
ORIGIN_SOURCES := $(wildcard src/*)
ORIGIN_SOURCES += $(wildcard $(BOUNDS_CHECK_LIB)/src/*)
C_SOURCES := $(filter %.c,$(ORIGIN_SOURCES))
YACC_SOURCES := $(filter %.y,$(ORIGIN_SOURCES))
LEX_SOURCES := $(filter %.l,$(ORIGIN_SOURCES))
YACC_GEN_SOURCES := $(patsubst %.y,$(OUT_DIR)/%_tab.c,$(YACC_SOURCES))
LEX_GEN_SOURCES := $(patsubst %.l,$(OUT_DIR)/%_lex.c,$(LEX_SOURCES))
C_OBJECTS := $(patsubst %.c,$(OUT_DIR)/%.o,$(C_SOURCES))
GEN_OBJECTS += $(patsubst %.c,%.o,$(YACC_GEN_SOURCES) $(LEX_GEN_SOURCES))
OBJECTS := $(GEN_OBJECTS) $(C_OBJECTS)
C_FLAGS += $(addprefix -I,$(INCLUDE_DIR))
INCLUDE_DIR += $(OUT_DIR)
UNAME := $(shell uname -a)
ifneq ($(findstring Linux,$(UNAME)),)
C_FLAGS += -D OS_LINUX
else
C_FLAGS += -D OS_WIN
C_FLAGS += -D MINGW32
endif
ifeq ($(BUILD_TYPE),debug)
C_FLAGS += -g
else ifeq ($(BUILD_TYPE),asan)
C_FLAGS += -g -fsanitize=address
else
# release
C_FLAGS += -O2 -s -ffunction-sections -fdata-sections -Wl,--gc-sections
endif
all: $(TARGET)
$(YACC_GEN_SOURCES) : $(OUT_DIR)/%_tab.c : %.y
$(Q)mkdir -p $(dir $(@))
$(Q)$(YACC) -o $@ -v -d -pHcsCompiler $<
$(TARGET):
$(Q)mkdir -p $(BUILD_DIR)
$(Q)pushd $(BUILD_DIR); cmake ../; popd
$(Q)make -C $(BUILD_DIR)
$(LEX_GEN_SOURCES) : $(OUT_DIR)/%_lex.c : %.l | $(YACC_GEN_SOURCES)
$(Q)mkdir -p $(dir $(@))
$(Q)$(LEX) -o $@ -PHcsCompiler $<
test: $(TARGET)
$(Q) python test/hcgen_test.py $(BUILD_DIR)/$(TARGET)
$(C_OBJECTS) : $(OUT_DIR)/%.o : %.c
$(Q)mkdir -p $(dir $(@))
$(Q)$(CC) -c -o $@ $(C_FLAGS) $^
$(GEN_OBJECTS) : %.o : %.c
$(Q)$(CC) -c -o $@ $(C_FLAGS) $^
$(TARGET) : $(OBJECTS) | $(GEN_OBJECTS)
$(Q)$(CC) -o $@ $(C_FLAGS) $^
test: all
python3 $(TEST_CASE)/hcgen_test.py $(TARGET)
test_update: all
python3 $(TEST_CASE)/update_case.py $(TARGET)
update_testcase: $(TARGET)
$(Q) python test/update_case.py $(BUILD_DIR)/$(TARGET)
clean:
$(Q)rm -rf $(OUT_DIR)
$(Q)rm -f $(TARGET)
$(Q) rm -rf $(BUILD_DIR)
.PHONY: clean all test test_update
.PHONY: all clean test $(TARGET)
Binary file not shown.
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2021, Huawei Device Co., Ltd. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import argparse
import platform
import subprocess
import time
def exec_command(cmd):
process = subprocess.Popen(cmd)
process.wait()
ret_code = process.returncode
if ret_code != 0:
raise Exception("{} failed, return code is {}".format(cmd, ret_code))
def make_hc_gen(current_dir):
exec_command(['make', '-C', current_dir])
def prepare(hc_gen, current_dir):
if not os.path.exists(hc_gen):
make_hc_gen(current_dir)
def main(argv):
current_dir = os.path.split(os.path.realpath(__file__))[0]
hc_gen = os.path.join(current_dir, 'build', 'hc-gen')
build_hcs_cmd = [hc_gen] + argv[1:]
prepare(hc_gen, current_dir)
exec_command(build_hcs_cmd)
if __name__ == '__main__':
sys.exit(main(sys.argv))
File diff suppressed because it is too large Load Diff
+440
View File
@@ -0,0 +1,440 @@
/*
* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_AST_H
#define HC_GEN_AST_H
#include <cstdint>
#include <string>
#include <memory>
#include <list>
#include <utility>
#include <vector>
#include "token.h"
#include "types.h"
namespace OHOS {
namespace Hardware {
enum ObjectType {
PARSEROP_UINT8 = 0x01,
PARSEROP_UINT16,
PARSEROP_UINT32,
PARSEROP_UINT64,
PARSEROP_STRING,
PARSEROP_CONFNODE,
PARSEROP_CONFTERM,
PARSEROP_ARRAY,
PARSEROP_NODEREF,
PARSEROP_DELETE,
};
enum NodeRefType {
NODE_NOREF = 0,
NODE_COPY,
NODE_REF,
NODE_DELETE,
NODE_TEMPLATE,
NODE_INHERIT,
};
class AstObject {
public:
friend class Ast;
AstObject(AstObject &obj);
AstObject(std::string name, uint32_t type, uint64_t value);
AstObject(std::string name, uint32_t type, std::string value);
AstObject(std::string name, uint32_t type, uint64_t value, const Token &bindToken);
AstObject(std::string name, uint32_t type, std::string value, const Token &bindToken);
virtual ~AstObject();
virtual bool AddChild(const std::shared_ptr<AstObject> &childObj);
virtual bool AddPeer(std::shared_ptr<AstObject> peerObject);
friend std::ostream &operator<<(std::ostream &stream, const AstObject &t);
virtual bool Merge(std::shared_ptr<AstObject> &srcObj);
virtual bool Copy(std::shared_ptr<AstObject> src, bool overwrite);
virtual bool Move(std::shared_ptr<AstObject> src);
void Remove();
void Separate();
std::shared_ptr<AstObject> Lookup(const std::string &name, uint32_t type = 0) const;
bool IsElders(const std::shared_ptr<AstObject> &child);
bool IsNumber() const;
bool IsNode() const;
bool IsTerm() const;
bool IsArray() const;
virtual std::string SourceInfo();
void SetParent(AstObject *parent);
void SetSize(uint32_t size);
void SetSubSize(uint32_t size);
void SetHash(uint32_t hash);
uint32_t GetSize();
uint32_t GetSubSize();
uint32_t GetHash();
std::shared_ptr<AstObject> Child();
std::shared_ptr<AstObject> Next();
virtual const std::string &Name();
const std::string &StringValue();
uint64_t IntegerValue();
virtual uint32_t Type();
uint8_t OpCode();
void SetOpCode(uint8_t opcode);
virtual bool HasDuplicateChild();
std::shared_ptr<AstObject> Parent();
protected:
uint32_t type_;
std::string name_;
AstObject *parent_;
std::shared_ptr<AstObject> next_;
std::shared_ptr<AstObject> child_;
uint32_t lineno_;
std::shared_ptr<std::string> src_;
uint8_t opCode_;
uint32_t size_;
uint32_t subSize_;
uint32_t hash_;
uint64_t integerValue_;
std::string stringValue_;
private:
static uint32_t FitIntegerValueType(uint64_t value);
};
class ConfigNode : public AstObject {
public:
ConfigNode(ConfigNode &node);
ConfigNode(std::string name, uint32_t nodeType, std::string refName);
ConfigNode(Token &name, uint32_t nodeType, std::string refName);
~ConfigNode() override = default;
friend std::ostream &operator<<(std::ostream &stream, const ConfigNode &t);
bool Merge(std::shared_ptr<AstObject> &srcObj) override;
static ConfigNode *CastFrom(const std::shared_ptr<AstObject> &astObject);
uint32_t GetNodeType() const;
const std::string &GetRefPath();
void SetNodeType(uint32_t type);
void SetRefPath(std::string ref);
static const std::string &NodeTypeToStr(uint32_t type);
bool HasDuplicateChild() override;
bool InheritExpand(const std::shared_ptr<AstObject> &refObj);
bool RefExpand(const std::shared_ptr<AstObject> &refObj);
bool Copy(std::shared_ptr<AstObject> src, bool overwrite) override;
bool Move(std::shared_ptr<AstObject> src) override;
bool Compare(ConfigNode &other);
uint32_t InheritIndex();
uint32_t InheritCount();
uint32_t TemplateSignNum();
void SetTemplateSignNum(uint32_t sigNum);
const std::list<AstObject *> &SubClasses();
private:
bool NodeRefExpand(const std::shared_ptr<AstObject> &ref);
bool NodeCopyExpand(const std::shared_ptr<AstObject> &ref);
std::string refNodePath_;
uint32_t nodeType_;
uint32_t inheritIndex_;
uint32_t inheritCount_;
uint32_t templateSignNum_;
std::list<AstObject *> subClasses_;
};
class ConfigTerm : public AstObject {
public:
ConfigTerm(ConfigTerm &term);
ConfigTerm(std::string name, const std::shared_ptr<AstObject> &value);
ConfigTerm(Token &name, const std::shared_ptr<AstObject> &value);
~ConfigTerm() override = default;
static ConfigTerm *CastFrom(const std::shared_ptr<AstObject> &astObject);
bool Merge(std::shared_ptr<AstObject> &srcObj) override;
friend std::ostream &operator<<(std::ostream &stream, const ConfigTerm &t);
bool RefExpand(std::shared_ptr<AstObject> refObject);
bool Copy(std::shared_ptr<AstObject> src, bool overwrite) override;
bool Move(std::shared_ptr<AstObject> src) override;
std::weak_ptr<AstObject> RefNode();
uint32_t SigNum();
void SetSigNum(uint32_t sigNum);
private:
std::weak_ptr<AstObject> refNode_;
uint32_t signNum_;
};
class ConfigArray : public AstObject {
public:
ConfigArray();
ConfigArray(ConfigArray &array);
explicit ConfigArray(const Token &bindToken);
~ConfigArray() override = default;
static ConfigArray *CastFrom(const std::shared_ptr<AstObject> &astObject);
bool AddChild(const std::shared_ptr<AstObject> &childObj) override;
bool Merge(std::shared_ptr<AstObject> &srcObj) override;
bool Copy(std::shared_ptr<AstObject> src, bool overwrite) override;
uint16_t ArraySize();
uint16_t ArrayType();
private:
uint32_t arrayType_;
uint32_t arraySize_;
};
class AstObjectFactory {
public:
static std::shared_ptr<AstObject> Build(std::shared_ptr<AstObject> object);
};
class Ast {
public:
Ast() = default;
explicit Ast(std::shared_ptr<AstObject> astRoot) : astRoot_(std::move(astRoot)), redefineChecked_(false) {}
~Ast() = default;
std::shared_ptr<AstObject> GetAstRoot();
bool Merge(const std::list<std::shared_ptr<Ast>> &astList);
bool Expand();
std::shared_ptr<AstObject> Lookup(const std::shared_ptr<AstObject> &startObj, const std::string &path);
template<typename T>
static bool WalkForward(const std::shared_ptr<AstObject> &startObject, T callback)
{
std::shared_ptr<AstObject> forwardWalkObj = startObject;
int32_t walkDepth = 0;
bool preVisited = false;
while (forwardWalkObj != nullptr) {
if (!preVisited) {
int32_t ret = callback(forwardWalkObj, walkDepth);
if (ret && ret != EASTWALKBREAK) {
return false;
} else if (ret != EASTWALKBREAK && forwardWalkObj->child_ != nullptr) {
/* when callback return EASTWALKBREAK, not walk current's child */
walkDepth++;
forwardWalkObj = forwardWalkObj->child_;
continue;
}
}
if (forwardWalkObj == startObject) {
break;
}
if (forwardWalkObj->next_ != nullptr) {
forwardWalkObj = forwardWalkObj->next_;
preVisited = false;
} else {
forwardWalkObj = forwardWalkObj->Parent();
preVisited = true;
walkDepth--;
}
}
return true;
}
template<typename T>
static bool WalkBackward(const std::shared_ptr<AstObject> &startObject, T callback)
{
std::shared_ptr<AstObject> backWalkObj = startObject;
std::shared_ptr<AstObject> next = nullptr;
std::shared_ptr<AstObject> parent = nullptr;
int32_t walkDepth = 0;
bool preVisited = false;
while (backWalkObj != nullptr) {
if (backWalkObj->child_ == nullptr || preVisited) {
next = backWalkObj->next_;
parent = backWalkObj->Parent();
/* can safe delete current in callback */
if (callback(backWalkObj, walkDepth) != NOERR) {
return false;
}
} else {
if (backWalkObj->child_) {
walkDepth++;
backWalkObj = backWalkObj->child_;
continue;
}
}
if (backWalkObj == startObject) {
break;
}
if (next != nullptr) {
backWalkObj = next;
preVisited = false;
} else {
backWalkObj = parent;
preVisited = true;
walkDepth--;
}
}
return true;
}
template<typename T1, typename T2>
static bool WalkRound(const std::shared_ptr<AstObject> &startObject, T1 forwardCallback, T2 backwardCallback)
{
std::shared_ptr<AstObject> roundWalkObj = startObject;
int32_t walkDepth = 0;
bool preVisited = false;
while (roundWalkObj != nullptr) {
if (preVisited) {
if (backwardCallback(roundWalkObj, walkDepth) != NOERR) {
return false;
}
} else {
int32_t ret = forwardCallback(roundWalkObj, walkDepth);
/* when callback return EASTWALKBREAK, not walk current's child */
if (ret && ret != EASTWALKBREAK) {
return false;
} else if (!ret && roundWalkObj->child_ != nullptr) {
walkDepth++;
roundWalkObj = roundWalkObj->child_;
continue;
}
}
if (roundWalkObj == startObject) {
break;
}
if (roundWalkObj->next_) {
roundWalkObj = roundWalkObj->next_;
preVisited = false;
} else {
roundWalkObj = roundWalkObj->Parent();
preVisited = true;
walkDepth--;
}
}
return true;
}
template<typename T>
bool WalkForward(T callback)
{
return WalkForward(astRoot_, callback);
}
template<typename T>
bool WalkBackward(T callback)
{
return WalkBackward(astRoot_, callback);
}
template<typename T1, typename T2>
bool WalkRound(T1 forwardCallback, T2 backwardCallback)
{
return WalkRound(astRoot_, forwardCallback, backwardCallback);
}
void Dump(const std::string &prefix = std::string());
private:
bool RedefineCheck();
bool NodeExpand();
bool InheritExpand();
std::list<std::string> SplitNodePath(const std::string &path, char separator);
std::shared_ptr<AstObject> astRoot_;
bool redefineChecked_;
};
} // Hardware
} // OHOS
#endif // HC_GEN_AST_H
+324
View File
@@ -0,0 +1,324 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "bytecode_gen.h"
#include <string>
#include "file.h"
#include "logger.h"
#include "opcode.h"
using namespace OHOS::Hardware;
ByteCodeGen::ByteCodeGen(std::shared_ptr<Ast> ast) : Generator(ast),
needAlign_(false)
{
}
bool ByteCodeGen::Output()
{
if (!Initialize()) {
return false;
}
if (!ByteCodeConvert()) {
return false;
}
if (!ByteCodeWrite(true)) {
return false;
}
if (!ByteCodeWrite(false)) {
return false;
}
if (Option::Instance().ShouldGenHexDump()) {
return Hexdump();
}
return true;
}
bool ByteCodeGen::Initialize()
{
auto opt = Option::Instance();
std::string outFileName = Util::File::StripSuffix(opt.GetOutputName());
if (outFileName.empty()) {
outFileName = opt.GetSourceNameBase() + ".hcb";
}
if (outFileName.find(".hcb") == std::string::npos) {
outFileName.append(".hcb");
}
ofs_.open(outFileName, std::ofstream::out | std::ofstream::binary);
if (!ofs_.is_open()) {
Logger().Error() << "failed to open output file: " << outFileName;
return false;
}
Logger().Debug() << "output: " << outFileName;
needAlign_ = opt.ShouldAlign();
outFileName_ = std::move(outFileName);
return true;
}
bool ByteCodeGen::ByteCodeConvert()
{
return ast_->WalkBackward([this](std::shared_ptr<AstObject> &object, uint32_t depth) {
if (object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() == NODE_TEMPLATE) {
object->Separate();
return NOERR;
}
auto opcode = ToOpCode(object->Type());
if (opcode.opCode == 0) {
Logger().Error() << object->SourceInfo() << "cannot covert type " << object->Type() << " to opcode";
return EINVALF;
}
object->SetOpCode(opcode.opCode);
CalculateSize(object);
return NOERR;
});
}
uint32_t ByteCodeGen::Align(uint32_t size) const
{
return needAlign_ ? ((size + ALIGN_SIZE - 1) & (~(ALIGN_SIZE - 1))) : size;
}
const OpCode &ByteCodeGen::ToOpCode(uint32_t objectType)
{
static std::map<uint32_t, OpCode> byteCodeMap = {
{PARSEROP_UINT8, {HCS_BYTE_OP, BYTE_SIZE, "Uint8"}},
{PARSEROP_UINT16, {HCS_WORD_OP, WORD_SIZE, "Uint16"}},
{PARSEROP_UINT32, {HCS_DWORD_OP, DWORD_SIZE, "Uint32"}},
{PARSEROP_UINT64, {HCS_QWORD_OP, QWORD_SIZE, "Uint64"}},
{PARSEROP_STRING, {HCS_STRING_OP, 0, "String"}},
{PARSEROP_ARRAY, {HCS_ARRAY_OP, WORD_SIZE, "Array"}}, /* ElementCount - WORD */
{PARSEROP_CONFNODE, {HCS_NODE_OP, DWORD_SIZE, "ConfigNode"}}, /* SubSize - DWORD */
{PARSEROP_CONFTERM, {HCS_TERM_OP, 0, "ConfigTerm"}},
{PARSEROP_NODEREF, {HCS_NODEREF_OP, DWORD_SIZE, "NodeRef"}}, /* RefHashCode - DWORD */
};
return byteCodeMap[objectType];
}
void ByteCodeGen::Write(const std::string &data)
{
Write(data.c_str(), static_cast<uint32_t>(data.size() + 1));
}
template<typename T>
void ByteCodeGen::Write(T &data)
{
auto p = &data;
uint32_t size = sizeof(data);
auto d = reinterpret_cast<const char *>(p);
Write(d, size);
}
void ByteCodeGen::Write(const char *data, uint32_t size)
{
FsWrite(data, size);
static char stubData[ALIGN_SIZE] = {0};
auto alignSize = Align(size);
auto stubSize = alignSize - size;
if (stubSize != 0) {
FsWrite(stubData, stubSize);
}
writeSize_ += alignSize;
}
void ByteCodeGen::CalculateSize(const std::shared_ptr<AstObject> &object)
{
uint32_t size = Align(OPCODE_BYTE_WIDTH) + Align(ToOpCode(object->Type()).size);
switch (object->OpCode()) {
case HCS_NODE_OP: /* fall-through */
case HCS_TERM_OP:
/* name string */
size += Align(object->Name().size() + 1); // add 1 for '\0'
break;
case HCS_STRING_OP:
size += Align(object->StringValue().size() + 1);
break;
default:
break;
}
auto child = object->Child();
uint32_t subSize = 0;
while (child != nullptr) {
subSize += child->GetSize();
child = child->Next();
}
object->SetSize(subSize + size);
object->SetSubSize(subSize);
}
bool ByteCodeGen::ByteCodeWrite(bool dummy)
{
dummyOutput_ = dummy;
writeSize_ = 0;
HcbHeader header = {
.magicNumber = HCB_MAGIC_NUM,
.versionMajor = 0,
.versionMinor = 0,
.checkSum = 0,
.totalSize = static_cast<int32_t>(Option::Instance().ShouldAlign() ? -ast_->GetAstRoot()->GetSize()
: ast_->GetAstRoot()->GetSize()),
};
Option::Instance().GetVersion(header.versionMinor, header.versionMajor);
Write(header);
if (WriteBad()) {
return false;
}
return ByteCodeWriteWalk();
}
bool ByteCodeGen::ByteCodeWriteWalk()
{
return ast_->WalkForward([this](std::shared_ptr<AstObject> &current, uint32_t depth) {
current->SetHash(writeSize_);
auto opcode = current->OpCode();
Write(opcode);
switch (current->OpCode()) {
case HCS_BYTE_OP:
case HCS_WORD_OP:
case HCS_DWORD_OP:
case HCS_QWORD_OP: {
auto value = current->IntegerValue();
Write(reinterpret_cast<const char *>(&value), ToOpCode(current->Type()).size);
break;
}
case HCS_STRING_OP:
Write(current->StringValue());
break;
case HCS_TERM_OP:
Write(current->Name());
break;
case HCS_NODE_OP: {
Write(current->Name());
auto subSize = current->GetSubSize();
Write(subSize);
break;
}
case HCS_ARRAY_OP: {
uint16_t arraySize = ConfigArray::CastFrom(current)->ArraySize();
Write(arraySize);
break;
}
case HCS_NODEREF_OP: {
auto term = ConfigTerm::CastFrom(current->Parent());
uint32_t hashCode = term->RefNode().lock()->GetHash();
Write(hashCode);
break;
}
default:
break;
}
if (WriteBad()) {
return EOUTPUT;
}
return NOERR;
});
}
void ByteCodeGen::FsWrite(const char *data, uint32_t size)
{
if (dummyOutput_)
return;
ofs_.write(data, size);
}
bool ByteCodeGen::WriteBad()
{
if (ofs_.bad()) {
Logger().Error() << "failed to write file " << outFileName_;
return true;
}
return false;
}
bool ByteCodeGen::HexdumpInitialize(FILE *&in, FILE *&out)
{
ofs_.close();
std::string hexdumpOutName = Util::File::StripSuffix(outFileName_).append("_hex.c");
in = fopen(outFileName_.data(), "rb");
if (in == nullptr) {
Logger().Error() << "failed to open " << outFileName_;
return false;
}
out = fopen(hexdumpOutName.data(), "wb");
if (out == nullptr) {
fclose(in);
in = nullptr;
Logger().Error() << "failed to open " << hexdumpOutName;
return false;
}
return true;
}
bool ByteCodeGen::Hexdump()
{
FILE *in = nullptr;
FILE *out = nullptr;
if (!HexdumpInitialize(in, out)) {
return false;
}
auto ret = HexdumpOutput(in, out);
fclose(in);
fclose(out);
return ret;
}
bool ByteCodeGen::HexdumpOutput(FILE *in, FILE *out)
{
constexpr const char *HCS_HEXDUMP_ENTRY_SYMBOL = "hdfConfigEntrySymbol";
constexpr const int PRINT_SKIP_STEP = 2;
constexpr const int NUMS_PER_LINE = 16;
std::string prefix = Option::Instance().GetSymbolPrefix();
if (fprintf(out, "static const unsigned char g_%s%s[] = {\n", prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL) < 0) {
return false;
}
uint32_t writeCount = 0;
int32_t byte;
while ((byte = getc(in)) != EOF) {
if (fprintf(out, "%s0x%02x", (writeCount % NUMS_PER_LINE) ? ", " : &",\n "[PRINT_SKIP_STEP * !writeCount],
byte) < 0) {
return false;
}
writeCount++;
}
if (fprintf(out, "\n};\n") < 0) {
return false;
}
if (fprintf(out, "static const unsigned int g_%sLen = %u;\n", HCS_HEXDUMP_ENTRY_SYMBOL, writeCount) < 0) {
return false;
}
if (fprintf(out,
"void HdfGetBuildInConfigData(const unsigned char** data, unsigned int* size)\n"
"{\n"
" *data = g_%s%s;\n"
" *size = g_%s%sLen;\n"
"}",
prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL, prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL) < 0) {
return false;
}
return true;
}
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_BYTECODE_GEN_H
#define HC_GEN_BYTECODE_GEN_H
#include <fstream>
#include <utility>
#include "generator.h"
namespace OHOS {
namespace Hardware {
struct OpCode {
OpCode() : opCode(0),
size(0) {}
OpCode(uint8_t code, uint32_t s, std::string str) : opCode(code),
size(s),
opStr(std::move(str)) {}
~OpCode() = default;
uint8_t opCode;
uint32_t size;
const std::string opStr;
};
class ByteCodeGen : public Generator {
public:
explicit ByteCodeGen(std::shared_ptr<Ast> ast);
~ByteCodeGen() override = default;
bool Output() override;
private:
bool Initialize();
bool ByteCodeConvert();
uint32_t Align(uint32_t size) const;
void CalculateSize(const std::shared_ptr<AstObject> &object);
bool ByteCodeWrite(bool dummy);
bool ByteCodeWriteWalk();
template<typename T>
void Write(T &data);
void Write(const char *data, uint32_t size);
void Write(const std::string &data);
void FsWrite(const char *data, uint32_t size);
static const OpCode &ToOpCode(uint32_t objectType);
bool WriteBad();
bool HexdumpInitialize(FILE *&in, FILE *&out);
static bool HexdumpOutput(FILE *in, FILE *out);
bool Hexdump();
bool needAlign_;
std::ofstream ofs_;
std::string outFileName_;
bool dummyOutput_;
uint32_t writeSize_;
};
} // Hardware
} // OHOS
#endif // HC_GEN_BYTECODE_GEN_H
+333
View File
@@ -0,0 +1,333 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "decompile.h"
#include <cctype>
#include "decompile_gen.h"
#include "logger.h"
#include "opcode.h"
using namespace OHOS::Hardware;
Decompile::Decompile(std::string fileName) : isAlign_(false), fileName_(std::move(fileName))
{
}
bool Decompile::InitDecompileFile()
{
file_.open(fileName_.data(), std::ios::binary);
if(!file_.is_open()) {
Logger().Error() << "Failed to open decompile file: " << fileName_;
return false;
}
return true;
}
bool Decompile::ReadFile(char *buffer, size_t readSize)
{
if(!file_.read(buffer, static_cast<std::streamsize>(readSize))) {
Logger().Error() << "read file failed, read size is: " << readSize;
return false;
}
return true;
}
void Decompile::SetAlign(bool isAlign)
{
isAlign_ = isAlign;
}
bool Decompile::VerifyDecompileFile()
{
HcbHeader header{0};
if (!ReadFile(reinterpret_cast<char *>(&header), sizeof(header))) {
Logger().Error() << "read header failed";
return false;
}
Logger().Debug() << "read Header: magic is: " << header.magicNumber << " version major: " << header.versionMajor <<
" version minor: " << header.versionMinor << " checksum: " << header.checkSum << " totalSize: " << header.totalSize;
if (header.magicNumber != HCB_MAGIC_NUM) {
Logger().Error() << "magic number is: " << header.magicNumber << ", check failed!";
return false;
}
if (header.totalSize < 0) {
SetAlign(true);
header.totalSize = -header.totalSize;
}
return true;
}
bool Decompile::ReadUint32(uint32_t &value)
{
return ReadFile(reinterpret_cast<char *>(&value), sizeof(uint32_t));
}
bool Decompile::ReadUint8(uint8_t &value)
{
if (GetAlignSize(sizeof(uint8_t)) != sizeof(uint8_t)) {
uint32_t readValue = 0;
if (!ReadUint32(readValue)) {
return false;
}
value = static_cast<uint8_t>(readValue);
return true;
}
return ReadFile(reinterpret_cast<char *>(&value), sizeof(uint8_t));
}
bool Decompile::ReadUint16(uint16_t &value)
{
if (GetAlignSize(sizeof(uint16_t)) != sizeof(uint16_t)) {
uint32_t readValue = 0;
if (!ReadUint32(readValue)) {
return false;
}
value = static_cast<uint16_t>(readValue);
return true;
}
return ReadFile(reinterpret_cast<char *>(&value), sizeof(uint16_t));
}
bool Decompile::ReadUint64(uint64_t &value)
{
return ReadFile(reinterpret_cast<char *>(&value), sizeof(uint64_t));
}
bool Decompile::ReadString(std::string &value)
{
value.clear();
char c;
while(ReadFile(&c, sizeof(c))) {
if (c == '\0') {
break;
}
if (value.length() > NUMBER) {
return false;
}
value += c;
}
uint32_t alignSize = GetAlignSize(value.length() + 1) - (value.length() + 1);
if (alignSize > 0) {
char alignReadBuff[4];
if (!ReadFile(alignReadBuff, alignSize)) {
return false;
}
}
return true;
}
bool Decompile::GetNextByteCode(uint32_t &byteCode)
{
if (GetAlignSize(OPCODE_BYTE_WIDTH) == OPCODE_BYTE_WIDTH) {
uint8_t value = 0;
bool ret = ReadUint8(value);
byteCode = value;
return ret;
} else {
return ReadUint32(byteCode);
}
}
std::shared_ptr<AstObject> Decompile::RebuildNode()
{
uint32_t nodeHash = static_cast<uint32_t>(file_.tellg()) - GetAlignSize(OPCODE_BYTE_WIDTH);
std::string nodeName;
if (!ReadString(nodeName)) {
return nullptr;
}
auto node = std::make_shared<ConfigNode>(nodeName, NODE_NOREF, "");
uint32_t nodeSize = 0;
if(!ReadUint32(nodeSize)) {
return nullptr;
}
node->SetSize(nodeSize);
node->SetHash(nodeHash);
Logger().Debug() << "node name is: " << node->Name() << ", size is: " << nodeSize << ", hash is: " << nodeHash;
uint32_t pos = file_.tellg();
uint32_t nodeEnd = pos + nodeSize;
while (pos < nodeEnd) {
uint32_t childOpCode;
if (!GetNextByteCode(childOpCode)) {
Logger().Error() << "Rebuild node failed, get next byte code failed";
return nullptr;
}
auto child = RebuildObject(childOpCode);
if (child == nullptr) {
Logger().Error() << "Rebuild node failed, get child failed";
return nullptr;
}
if (!node->AddChild(child)) {
Logger().Error() << "Rebuild node failed, add child failed";
return nullptr;
}
pos = file_.tellg();
}
return node;
}
std::shared_ptr<AstObject> Decompile::RebuildTerm()
{
std::string termName;
if (!ReadString(termName)) {
return nullptr;
}
uint32_t childOpCode;
if (!GetNextByteCode(childOpCode)) {
return nullptr;
}
auto value = RebuildObject(childOpCode);
if (value == nullptr) {
return nullptr;
}
return std::make_shared<ConfigTerm>(termName, value);
}
std::shared_ptr<AstObject> Decompile::RebuildNodeRefObject()
{
uint32_t refNodeHash = 0;
if (!ReadUint32(refNodeHash)) {
return nullptr;
}
Logger().Debug() << "Ref object value is: " << refNodeHash;
return std::make_shared<AstObject>(std::string(), PARSEROP_NODEREF, refNodeHash);
}
std::shared_ptr<AstObject> Decompile::RebuildNumberObject(uint8_t opCode)
{
uint8_t u8Value = 0;
uint16_t u16Value = 0;
uint32_t u32Value = 0;
uint64_t u64Value = 0;
switch (opCode) {
case HCS_BYTE_OP:
if (!ReadUint8(u8Value)) {
return nullptr;
}
return std::make_shared<AstObject>(std::string(), PARSEROP_UINT8, u8Value);
case HCS_WORD_OP:
if (!ReadUint16(u16Value)) {
return nullptr;
}
return std::make_shared<AstObject>(std::string(), PARSEROP_UINT16, u16Value);
case HCS_DWORD_OP:
if (!ReadUint32(u32Value)) {
return nullptr;
}
return std::make_shared<AstObject>(std::string(), PARSEROP_UINT32, u32Value);
case HCS_QWORD_OP:
if (!ReadUint64(u64Value)) {
return nullptr;
}
return std::make_shared<AstObject>(std::string(), PARSEROP_UINT64, u64Value);
default:
return nullptr;
}
}
std::shared_ptr<AstObject> Decompile::RebuildArray()
{
uint16_t arraySize = 0;
if (!ReadUint16(arraySize)) {
return nullptr;
}
auto array = std::make_shared<AstObject>(std::string(), PARSEROP_ARRAY, 0);
if (array == nullptr) {
return nullptr;
}
for (uint16_t i = 0; i < arraySize; i++) {
uint32_t opCode = 0;
if (!GetNextByteCode(opCode)) {
return nullptr;
}
auto element = RebuildObject(opCode);
if (element == nullptr) {
return nullptr;
}
if (!array->AddChild(element)) {
return nullptr;
}
}
return array;
}
std::shared_ptr<AstObject> Decompile::RebuildStringObject()
{
std::string strValue;
if (!ReadString(strValue)) {
return nullptr;
}
return std::make_shared<AstObject>(std::string(), PARSEROP_STRING, strValue);
}
std::shared_ptr<AstObject> Decompile::RebuildObject(uint8_t opCode)
{
switch (opCode) {
case HCS_NODE_OP:
return RebuildNode();
case HCS_TERM_OP:
return RebuildTerm();
case HCS_NODEREF_OP:
return RebuildNodeRefObject();
case HCS_BYTE_OP:
case HCS_WORD_OP:
case HCS_DWORD_OP:
case HCS_QWORD_OP:
return RebuildNumberObject(opCode);
case HCS_ARRAY_OP:
return RebuildArray();
case HCS_STRING_OP:
return RebuildStringObject();
default:
Logger().Error() << "Rebuild object failed, unknown OpCode is: " << opCode;
break;
}
return nullptr;
}
std::shared_ptr<Ast> Decompile::RebuildAst()
{
uint32_t currByteCode = 0;
if (!GetNextByteCode(currByteCode) || currByteCode != HCS_NODE_OP) {
Logger().Error() << "Rebuild Ast failed, miss root node!";
return nullptr;
}
auto rootObject = RebuildObject(currByteCode);
if (rootObject == nullptr) {
Logger().Error() << "Rebuild Ast failed, rebuild object failed!";
return nullptr;
}
auto ast = std::make_shared<Ast>(rootObject);
ast->Dump();
return ast;
}
bool Decompile::DoDecompile()
{
if(!InitDecompileFile()) {
return false;
}
if (!VerifyDecompileFile()) {
Logger().Error() << "Verify decompile file failed!";
return false;
}
auto ast = RebuildAst();
if (ast == nullptr) {
Logger().Error() << "Rebuild ast failed!";
return false;
}
std::string outPutFileName = Option::Instance().GetOutputName();
if (outPutFileName.empty()) {
outPutFileName = Option::Instance().GetSourceName();
} else if (!isalpha(outPutFileName[outPutFileName.length() - 1])) {
outPutFileName.append(Option::Instance().GetSourceNameBase());
}
DecompileGen decompileGen(ast, outPutFileName);
return decompileGen.OutPut();
}
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_DECOMPILE_H
#define HC_GEN_DECOMPILE_H
#include <fstream>
#include <string>
#include "ast.h"
namespace OHOS {
namespace Hardware {
class Decompile {
public:
explicit Decompile(std::string fileName);
~Decompile() = default;
bool DoDecompile();
private:
bool InitDecompileFile();
bool ReadFile(char *buffer, size_t readSize);
uint32_t GetAlignSize(uint32_t size)
{
if (isAlign_) {
return (size + ALIGN_SIZE - 1) & (~(ALIGN_SIZE - 1));
} else {
return size;
}
}
bool ReadUint8(uint8_t &value);
bool ReadUint16(uint16_t &value);
bool ReadUint32(uint32_t &value);
bool ReadUint64(uint64_t &value);
bool ReadString(std::string &value);
void SetAlign(bool isAlign);
bool VerifyDecompileFile();
bool GetNextByteCode(uint32_t &byteCode);
std::shared_ptr<AstObject> RebuildObject(uint8_t opCode);
std::shared_ptr<AstObject> RebuildNode();
std::shared_ptr<AstObject> RebuildTerm();
std::shared_ptr<AstObject> RebuildNodeRefObject();
std::shared_ptr<AstObject> RebuildNumberObject(uint8_t opCode);
std::shared_ptr<AstObject> RebuildArray();
std::shared_ptr<AstObject> RebuildStringObject();
std::shared_ptr<Ast> RebuildAst();
bool isAlign_;
std::string fileName_;
std::ifstream file_;
};
} // OHOS
} // Hardware
#endif // HC_GEN_DECOMPILE_H
+187
View File
@@ -0,0 +1,187 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "decompile_gen.h"
#include <sstream>
#include "file.h"
#include "logger.h"
using namespace OHOS::Hardware;
DecompileGen::DecompileGen(std::shared_ptr<Ast> ast, std::string outPutFileName) : ast_(ast)
{
outPutFileName_ = Util::File::StripSuffix(std::move(outPutFileName)).append(".d.hcs");
Logger().Debug() << "Decompile gen file: " << outPutFileName_;
}
bool DecompileGen::Init()
{
file_.open(outPutFileName_, std::ostream::out | std::ostream::binary);
if (!file_.is_open()) {
Logger().Error() << "Failed to open decompile output file: " << outPutFileName_;
return false;
}
return true;
}
void DecompileGen::WriteFile(const std::string &str)
{
file_ << str;
}
std::string DecompileGen::GetNodeRefPath(uint32_t value)
{
std::string refPath;
std::shared_ptr<AstObject> astObject = ast_->GetAstRoot();
if (astObject == nullptr) {
return refPath;
}
while (astObject->Child() != nullptr) {
refPath = astObject->Name() + ".";
auto child = astObject->Child();
bool deepIn = false;
while (child != nullptr) {
if (child->Type() != PARSEROP_CONFNODE) {
child = child->Next();
continue;
}
if (child->GetHash() == value) {
return (refPath + child->Name());
}
if (value > child->GetHash() && value < (child->GetHash() + child->GetSize())) {
astObject = child;
deepIn = true;
break;
}
child = child->Next();
}
if (!deepIn) {
Logger().Error() << "ref unknown node, hash = " << value;
break;
}
}
return std::string();
}
int32_t DecompileGen::PrintArrayType(const std::shared_ptr<AstObject>& astObj)
{
WriteFile("[");
auto arrayElement = astObj->Child();
while (arrayElement->Next()) {
if (PrintBaseType(arrayElement) != NOERR) {
return EOUTPUT;
}
WriteFile(", ");
arrayElement = arrayElement->Next();
}
if (PrintBaseType(arrayElement) != NOERR) {
return EOUTPUT;
}
WriteFile("]");
return NOERR;
}
int32_t DecompileGen::PrintBaseType(const std::shared_ptr<AstObject>& astObj)
{
std::stringstream outStr;
std::string refPath;
switch (astObj->Type()) {
case PARSEROP_UINT8:
case PARSEROP_UINT16:
case PARSEROP_UINT32:
case PARSEROP_UINT64:
outStr << "0x" << std::uppercase << std::hex << astObj->IntegerValue();
WriteFile(outStr.str());
break;
case PARSEROP_STRING:
outStr << "\"" << astObj->StringValue() << "\"";
WriteFile(outStr.str());
break;
case PARSEROP_NODEREF:
refPath = GetNodeRefPath(astObj->IntegerValue());
if (refPath.empty()) {
return EOUTPUT;
}
WriteFile("&" + refPath);
break;
case PARSEROP_ARRAY:
return PrintArrayType(astObj);
default:
Logger().Error() << "unknown opcode = " << astObj->Type();
return EFAIL;
}
return NOERR;
}
int32_t DecompileGen::OutPutWalk(const std::shared_ptr<AstObject>& astObj, int32_t walkDepth)
{
if (astObj->Type() != PARSEROP_CONFNODE && astObj->Type() != PARSEROP_CONFTERM) {
return NOERR;
}
int ret;
std::string tabStr = std::string(TAB_SIZE * walkDepth, ' ');
if (walkDepth != 0) {
WriteFile(tabStr);
}
std::string str;
switch (astObj->Type()) {
case PARSEROP_CONFNODE:
str = astObj->Name() + " {\n";
WriteFile(str);
if (astObj->Child() == nullptr) {
tabStr += "}\n";
WriteFile(tabStr);
}
break;
case PARSEROP_CONFTERM:
str = astObj->Name() + " = ";
WriteFile(str);
ret = PrintBaseType(astObj->Child());
if (ret != NOERR) {
return ret;
}
WriteFile(";\n");
break;
default:
return EOUTPUT;
}
return 0;
}
int32_t DecompileGen::CloseBrace(const std::shared_ptr<AstObject>& astObj, int32_t walkDepth)
{
if (astObj->Type() != PARSEROP_CONFNODE) {
return NOERR;
}
std::string tabStr = std::string(TAB_SIZE * walkDepth, ' ');
if (astObj != ast_->GetAstRoot()) {
WriteFile(tabStr + "}\n");
} else {
WriteFile("}\n");
}
return file_.good() ? NOERR : EOUTPUT;
}
bool DecompileGen::OutPut()
{
if (!Init()) {
return false;
}
WriteFile(fileHeader_);
if (!ast_->WalkRound(
[this](std::shared_ptr<AstObject> &current, int32_t walkDepth) -> int32_t {
return OutPutWalk(current, walkDepth);
},
[this](std::shared_ptr<AstObject> &current, int32_t walkDepth) -> int32_t {
return CloseBrace(current, walkDepth);
})) {
return false;
}
return file_.good();
}
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_DECOMPILE_GEN_H
#define HC_GEN_DECOMPILE_GEN_H
#include <fstream>
#include <string>
#include "ast.h"
namespace OHOS {
namespace Hardware {
class DecompileGen {
public:
DecompileGen(std::shared_ptr<Ast> ast, std::string outPutFileName);
~DecompileGen() = default;
bool OutPut();
private:
bool Init();
void WriteFile(const std::string &str);
int32_t PrintBaseType(const std::shared_ptr<AstObject>& astObj);
std::string GetNodeRefPath(uint32_t hash);
int32_t PrintArrayType(const std::shared_ptr<AstObject>& astObj);
int32_t OutPutWalk(const std::shared_ptr<AstObject>& astObj, int32_t walkDepth);
int32_t CloseBrace(const std::shared_ptr<AstObject>& astObj, int32_t walkDepth);
const std::string fileHeader_ = "/*\n * HDF decompile hcs file\n */\n\n";
std::string outPutFileName_;
std::ofstream file_;
std::shared_ptr<Ast> ast_;
};
} // OHOS
} // Hardware
#endif // HC_GEN_DECOMPILE_GEN_H
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "file.h"
#include <climits>
#include <cstdlib>
#include <unistd.h>
#include "types.h"
using namespace OHOS::Hardware::Util;
std::string File::AbsPath(const std::string& path)
{
char realPath[PATH_MAX];
#ifdef MINGW32
char *p = _fullpath(realPath, path.data(), PATH_MAX);
if (p != nullptr && access(p, F_OK) != 0) {
p = nullptr;
}
#else
char *p = realpath(path.data(), realPath);
#endif
return p == nullptr ? "" : p;
}
std::string File::StripSuffix(std::string path)
{
auto sepPos = path.rfind(OS_SEPARATOR);
auto dotPos = path.rfind('.');
if (sepPos == std::string::npos || dotPos > sepPos) {
return path.substr(0, dotPos);
} else {
return path;
}
}
std::string File::GetDir(std::string path)
{
auto separatorPos = path.rfind(OS_SEPARATOR);
if (separatorPos == std::string::npos) {
return path;
}
return path.substr(0, separatorPos + 1);
}
std::string File::FileNameBase(const std::string& path)
{
auto sepPos = path.rfind(OS_SEPARATOR);
auto dotPos = path.rfind('.');
if (sepPos == std::string::npos) {
sepPos = 0;
} else {
sepPos++;
}
if (dotPos == std::string::npos || dotPos < sepPos) {
dotPos = path.size();
}
auto len = path.size() - 1;
if (dotPos != std::string::npos && dotPos > sepPos) {
len = dotPos - sepPos;
}
return path.substr(sepPos, len);
}
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_FILE_H
#define HC_GEN_FILE_H
#include <string>
namespace OHOS {
namespace Hardware {
namespace Util {
class File {
public:
static std::string AbsPath(const std::string& path);
static std::string StripSuffix(std::string path);
static std::string GetDir(std::string path);
static std::string FileNameBase(const std::string& path);
};
} // Util
} //Hardware
} //OHOS
#endif // HC_GEN_FILE_H
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_GENERATOR_H
#define HC_GEN_GENERATOR_H
#include <memory>
#include <string>
#include "ast.h"
namespace OHOS {
namespace Hardware {
class Generator {
public:
Generator(std::shared_ptr<Ast> ast) : ast_(ast) {};
virtual ~Generator() = default;
virtual bool Output() = 0;
protected:
std::shared_ptr<Ast> ast_;
};
} // Hardware
} // OHOS
#endif // HC_GEN_GENERATOR_H
+381
View File
@@ -0,0 +1,381 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "lexer.h"
#include <sstream>
#include <string>
#include "logger.h"
using namespace OHOS::Hardware;
Lexer::Lexer() : lineno_(0), lineLoc_(0)
{
}
std::map<std::string, TokenType> Lexer::keyWords_ = {
{"#include", INCLUDE},
{"root", ROOT},
{"delete", DELETE},
{"template", TEMPLATE},
};
bool Lexer::Initialize(const std::string &sourceName)
{
srcName_ = std::make_shared<std::string>(sourceName);
if (src_.is_open()) {
src_.close();
}
bufferStart_ = nullptr;
bufferEnd_ = nullptr;
lineno_ = 1;
lineLoc_ = 1;
src_.open(srcName_->c_str(), std::ifstream::binary);
if (!src_.is_open()) {
Logger().Error() << "Failed to open source file: " << srcName_->data();
return false;
}
return true;
}
bool Lexer::Lex(Token &token)
{
char c;
InitToken(token);
do {
if (!PeekChar(c, true)) {
token.type = EOF;
return true;
}
if (c == '#') {
return LexInclude(token);
}
if (isalpha(c)) {
LexFromLiteral(token);
return true;
}
if (IsNum(c)) {
return LexFromNumber(token);
}
switch (c) {
case '/':
if (!ProcessComment()) {
return false;
}
continue;
case ';': /* fall-through */
case ',': /* fall-through */
case '[': /* fall-through */
case ']': /* fall-through */
case '{': /* fall-through */
case '}': /* fall-through */
case '=': /* fall-through */
case '&': /* fall-through */
case ':':
ConsumeChar();
token.type = c;
token.lineNo = lineno_;
break;
case '"':
return LexFromString(token);
case '+': /* fall-through */
case '-':
return LexFromNumber(token);
case EOF:
token.type = EOF;
break;
default:
Logger().Error() << *this << "can not recognized character '" << c << "'";
return false;
}
break;
} while (true);
return true;
}
char Lexer::GetRawChar()
{
if (!FillBuffer()) {
return EOF;
}
lineLoc_++;
return *bufferStart_++;
}
bool Lexer::GetChar(char &c, bool skipSpace)
{
char chr = GetRawChar();
if (skipSpace) {
while (IsSpace(chr)) {
chr = GetRawChar();
}
}
if (chr == '\n') {
lineno_++;
lineLoc_ = 0;
}
c = chr;
return chr != EOF;
}
bool Lexer::PeekChar(char &c, bool skipSpace)
{
if (!FillBuffer()) {
return false;
}
if (skipSpace) {
while (bufferStart_ <= bufferEnd_ && (IsSpace(*bufferStart_) || *bufferStart_ == '\n')) {
lineLoc_++;
if (*bufferStart_ == '\n') {
lineLoc_ = 0;
lineno_++;
}
bufferStart_++;
}
}
if (bufferStart_ > bufferEnd_) {
return false;
}
c = *bufferStart_;
return true;
}
bool Lexer::IsSpace(char c)
{
return c == ' ' || c == '\t' || c == '\r';
}
bool Lexer::FillBuffer()
{
if (bufferStart_ != nullptr && bufferStart_ <= bufferEnd_) {
return true;
}
auto size = src_.readsome(buffer_, BUFFER_SIZE);
if (size == 0) {
return false;
}
bufferStart_ = buffer_;
bufferEnd_ = bufferStart_ + size - 1;
return true;
}
bool Lexer::ProcessComment()
{
char c;
ConsumeChar();// skip first '/'
if (!GetChar(c)) {
Logger().Error() << *this << "unterminated comment";
return false;
}
if (c == '/') {
while (c != '\n' && GetChar(c)) {
}
if (c != '\n' && c != EOF) {
Logger().Error() << *this << "unterminated signal line comment";
return false;
}
} else if (c == '*') {
while (GetChar(c)) {
if (c == '*' && GetChar(c) && c == '/') {
return true;
}
}
if (c != '/') {
Logger().Error() << *this << "unterminated multi-line comment";
return false;
}
} else {
Logger().Error() << *this << "invalid character";
return false;
}
return true;
}
std::shared_ptr<std::string> Lexer::GetSourceName() const
{
return srcName_;
}
int32_t Lexer::GetLineno() const
{
return lineno_;
}
int32_t Lexer::GetLineLoc() const
{
return lineLoc_;
}
std::ostream &OHOS::Hardware::operator<<(std::ostream &stream, const Lexer &p)
{
return stream << p.GetSourceName()->data() << ":" << p.GetLineno() << ":" << p.GetLineLoc() << ": ";
}
void Lexer::InitToken(Token &token)
{
token.type = 0;
token.numval = 0;
token.strval.clear();
token.src = srcName_;
token.lineNo = lineno_;
}
bool Lexer::LexFromString(Token &token)
{
char c;
GetChar(c, false); // skip first '"'
std::string value;
while (GetChar(c, false) && c != '"') {
value.push_back(c);
}
if (c != '"') {
Logger().Error() << *this << "unterminated string";
return false;
}
token.type = STRING;
token.strval = std::move(value);
token.lineNo = lineno_;
return true;
}
bool Lexer::LexFromNumber(Token &token)
{
std::string value;
char c;
uint64_t v = 0;
GetChar(c, false);
switch (c) {
case '0':
if (!PeekChar(c, true)) {
break;
}
if (IsNum(c)) { // Octal number
while (PeekChar(c) && IsNum(c)) {
ConsumeChar();
value.push_back(c);
}
v = strtoll(value.data(), nullptr, 8);
break;
}
switch (c) {
case 'x': // fall-through
case 'X': // hex number
ConsumeChar();
while (PeekChar(c, false) && (IsNum(c) || (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F'))) {
value.push_back(c);
ConsumeChar();
}
v = strtoll(value.data(), nullptr, 16);
break;
case 'b': // binary number
ConsumeChar();
while (PeekChar(c, false) && (c == '0' || c == '1')) {
value.push_back(c);
ConsumeChar();
}
v = strtoll(value.data(), nullptr, 2);
break;
default:; // fall-through
}
break;
case '+': // fall-through
case '-': // fall-through, signed decimal number
default: // unsigned decimal number
value.push_back(c);
while (PeekChar(c, true) && IsNum(c)) {
ConsumeChar();
value.push_back(c);
}
v = strtoll(value.data(), nullptr, 10);
break;
}
if (errno != 0) {
Logger().Error() << *this << "illegal number: " << value.data();
return false;
}
token.type = NUMBER;
token.numval = v;
token.lineNo = lineno_;
return true;
}
void Lexer::LexFromLiteral(Token &token)
{
std::string value;
char c;
while (PeekChar(c, false) && !IsSpace(c)) {
if (!isalnum(c) && c != '_' && c != '.' && c != '\\') {
break;
}
value.push_back(c);
ConsumeChar();
}
do {
if (value == "true") {
token.type = NUMBER;
token.numval = 1;
break;
} else if (value == "false") {
token.type = NUMBER;
token.numval = 0;
break;
}
auto keyword = keyWords_.find(value);
if (keyword != keyWords_.end()) {
token.type = keyword->second;
break;
}
if (value.find('.') != std::string::npos) {
token.type = REF_PATH;
} else {
token.type = LITERAL;
}
} while (false);
token.strval = std::move(value);
token.lineNo = lineno_;
}
void Lexer::ConsumeChar()
{
char c;
(void) GetChar(c, false);
}
bool Lexer::IsNum(char c)
{
return c >= '0' && c <= '9';
}
bool Lexer::LexInclude(Token &token)
{
ConsumeChar();
LexFromLiteral(token);
if (token.strval != "include") {
return false;
}
token.type = INCLUDE;
return true;
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_LEXER_H
#define HC_GEN_LEXER_H
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include "token.h"
namespace OHOS {
namespace Hardware {
class Lexer {
public:
Lexer();
~Lexer() = default;
bool Initialize(const std::string &sourceName);
bool Lex(Token &token);
friend std::ostream &operator<<(std::ostream &stream, const Lexer &p);
std::shared_ptr<std::string> GetSourceName() const;
int32_t GetLineno() const;
int32_t GetLineLoc() const;
private:
static constexpr int BUFFER_SIZE = (1024 * 1024);
void InitToken(Token &token);
bool GetChar(char &c, bool skipSpace = true);
void ConsumeChar();
char GetRawChar();
static bool IsSpace(char c);
static bool IsNum(char c);
bool FillBuffer();
bool ProcessComment();
bool LexInclude(Token &token);
bool LexFromString(Token &token);
bool LexFromNumber(Token &token);
void LexFromLiteral(Token &token);
bool PeekChar(char &c, bool skipSpace = true);
static std::map<std::string, TokenType> keyWords_;
std::ifstream src_;
std::shared_ptr<std::string> srcName_;
char buffer_[BUFFER_SIZE]{0};
const char *bufferStart_{nullptr};
const char *bufferEnd_{nullptr};
int32_t lineno_;
int32_t lineLoc_;
};
} // Hardware
} // OHOS
#endif // HC_GEN_LEXER_H
+120
View File
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_LOG_H
#define HC_GEN_LOG_H
#include <iostream>
#include <map>
#include <string>
#include "option.h"
namespace OHOS {
namespace Hardware {
class Logger {
public:
Logger() : level_(INFO) {};
inline ~Logger()
{
if (level_ > INFO) {
::std::cout << ERROR_COLOR_END;
}
if (level_ <= DEBUG && !Option::Instance().VerboseLog()) {
return;
}
::std::cout << ::std::endl;
}
template<typename T>
inline Logger &operator<<(const T &v)
{
if (level_ <= DEBUG && !Option::Instance().VerboseLog()) {
return *this;
}
::std::cout << v;
return *this;
}
inline Logger &Debug()
{
level_ = DEBUG;
if (Option::Instance().VerboseLog()) {
ShowLevel();
}
return *this;
}
inline Logger &Info()
{
level_ = INFO;
ShowLevel();
return *this;
}
inline Logger &Warning()
{
level_ = WARNING;
ShowLevel();
return *this;
}
inline Logger &Error()
{
level_ = ERROR;
ShowLevel();
return *this;
}
inline Logger &Fatal()
{
level_ = FATAL;
ShowLevel();
return *this;
}
private:
enum LogLevel {
NONE,
DEBUG,
INFO,
WARNING,
ERROR,
FATAL,
} level_;
void ShowLevel()
{
static ::std::map<LogLevel, ::std::string> levelStrMap = {
{NONE, ""},
{DEBUG, "Debug"},
{INFO, "Info"},
{WARNING, "Warning"},
{ERROR, "Error"},
{FATAL, "Fatal"}
};
if (level_ > INFO) {
::std::cout << ERROR_COLOR_PREFIX;
}
::std::cout << "[" << levelStrMap[level_] << "] ";
}
#ifdef OS_LINUX
static constexpr const char *ERROR_COLOR_PREFIX = "\033[31m";
static constexpr const char *ERROR_COLOR_END = "\033[0m";
#else
static constexpr const char *ERROR_COLOR_PREFIX = "";
static constexpr const char *ERROR_COLOR_END = "";
#endif
};
} // OHOS
} // Hardware
#endif // HC_GEN_LOG_H
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "bytecode_gen.h"
#include "decompile.h"
#include "option.h"
#include "parser.h"
#include "text_gen.h"
using namespace OHOS::Hardware;
int main(int argc, char *argv[])
{
auto option = Option::Instance().Parse(argc, argv);
if (option.OptionError()) {
return EFAIL;
}
if (option.ShouldShowUsage()) {
option.ShowUsage();
return option.OptionError();
}
if (option.ShouldShowVersion()) {
option.ShowVersion();
return 0;
}
if (option.ShouldDecompile()) {
Decompile decompile(option.GetSourceName());
return decompile.DoDecompile() ? 0 : EFAIL;
}
Parser parser;
if (!parser.Parse()) {
return EFAIL;
}
if (option.ShouldGenBinaryConfig()) {
if (!ByteCodeGen(parser.GetAst()).Output()) {
return EFAIL;
}
return 0;
}
if (option.ShouldGenTextConfig()) {
if (!TextGen(parser.GetAst()).Output()) {
return EFAIL;
}
}
return 0;
}
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_OPCODE_H
#define HC_GEN_OPCODE_H
#include <cstdint>
#include <string>
#include "ast.h"
namespace OHOS {
namespace Hardware {
constexpr uint32_t HCB_MAGIC_NUM = 0xA00AA00A;
enum OpCodeType {
HCS_NODE_OP = 0x01,
HCS_TERM_OP = 0x02,
HCS_NODEREF_OP = 0x03,
HCS_ARRAY_OP = 0x04,
HCS_BYTE_OP = 0x10,
HCS_WORD_OP = 0x11,
HCS_DWORD_OP = 0x12,
HCS_QWORD_OP = 0x13,
HCS_STRING_OP = 0x14,
};
struct HcbHeader {
uint32_t magicNumber;
uint32_t versionMajor;
uint32_t versionMinor;
uint32_t checkSum;
int32_t totalSize;
};
} // OHOS
} // Hardware
#endif // HC_GEN_OPCODE_H
+228
View File
@@ -0,0 +1,228 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "option.h"
#include <cstring>
#include <getopt.h>
#include <iostream>
#include <iomanip>
#include "logger.h"
#include "file.h"
using namespace OHOS::Hardware;
static constexpr int HCS_COMPILER_VERSION_MAJOR = 00;
static constexpr int HCS_COMPILER_VERSION_MINOR = 7;
static constexpr int ARG_COUNT_MIN = 2;
Option &Option::Instance()
{
static Option option;
return option;
}
static constexpr int OPTION_END = -1;
static constexpr const char *HCS_SUPPORT_ARGS = "o:ap:bditvVh";
Option &Option::Parse(int argc, char **argv)
{
do {
if (argc < ARG_COUNT_MIN) {
showUsage_ = true;
break;
}
if (!ParseOptions(argc, argv)) {
break;
}
if (optind >= argc) {
Logger().Error() << "Miss input file name";
SetOptionError();
break;
}
SetSourceOption(argv[optind]);
return *this;
} while (false);
return *this;
}
bool Option::ParseOptions(int argc, char **argv)
{
int32_t op = 0;
while (op != OPTION_END) {
op = getopt(argc, argv, HCS_SUPPORT_ARGS);
switch (op) {
case 'o':
outputName_ = optarg;
break;
case 'a':
shouldAlign_ = true;
break;
case 'b':
shouldGenByteCodeConfig_ = true;
break;
case 't':
shouldGenTextConfig_ = true;
shouldGenByteCodeConfig_ = false;
break;
case 'p':
symbolNamePrefix_ = optarg;
break;
case 'i':
showGenHexDump_ = true;
break;
case 'V':
verboseLog_ = true;
break;
case 'd':
shouldDecompile_ = true;
break;
case 'v':
showVersion_ = true;
return false;
case 'h': /* fall-through */
showUsage_ = true;
return false;
case '?':
showUsage_ = true;
optionError_ = true;
SetOptionError();
return false;
default:
break;
}
}
return true;
}
void Option::ShowUsage()
{
Logger() <<
"Usage: hc-gen [Options] [File]\n" <<
"options:";
ShowOption("-a", "hcb align with four bytes");
ShowOption("-b", "output binary output, default enable");
ShowOption("-t", "output config in C language source file style");
ShowOption("-i", "output binary hex dump in C language source file style");
ShowOption("-p <prefix>", "prefix of generated symbol name");
ShowOption("-d", "decompile hcb to hcs");
ShowOption("-V", "show verbose info");
ShowOption("-v", "show version");
ShowOption("-h", "show this help message");
}
void Option::ShowOption(const ::std::string &option, const ::std::string &helpInfo)
{
Logger() << " " << ::std::setw(12) << ::std::left << option << " " << helpInfo;
}
bool Option::ShouldShowUsage() const
{
return showUsage_;
}
void Option::ShowVersion()
{
Logger() << "Hcs compiler " << HCS_COMPILER_VERSION_MAJOR << "." << HCS_COMPILER_VERSION_MINOR;
Logger() << "Copyright (c) 2020-2021 Huawei Device Co., Ltd.";
}
bool Option::OptionError() const
{
return optionError_;
}
bool Option::ShouldShowVersion() const
{
return showVersion_;
}
bool Option::ShouldAlign() const
{
return shouldAlign_;
}
bool Option::ShouldGenTextConfig() const
{
return shouldGenTextConfig_;
}
bool Option::ShouldGenBinaryConfig() const
{
return shouldGenByteCodeConfig_;
}
bool Option::ShouldGenHexDump() const
{
return showGenHexDump_;
}
bool Option::ShouldDecompile() const
{
return shouldDecompile_;
}
std::string Option::GetSymbolPrefix()
{
return symbolNamePrefix_;
}
bool Option::VerboseLog() const
{
return verboseLog_;
}
void Option::SetOptionError(bool shouldShowUsage)
{
showUsage_ = shouldShowUsage;
optionError_ = true;
}
std::string Option::GetSourceName()
{
return sourceName_;
}
std::string Option::GetSourceNameBase()
{
return sourceNameBase_;
}
std::string Option::GetOutputName()
{
return outputName_;
}
std::string Option::GetSourceDir()
{
return sourceDir_;
}
bool Option::SetSourceOption(const char *srcName)
{
std::string srcAbsPath;
srcAbsPath = Util::File::AbsPath(srcName);
if (srcAbsPath.empty()) {
Logger().Error() << "invalid source file: " << srcName << ", " << strerror(errno);
SetOptionError(false);
return false;
}
sourceName_ = srcAbsPath;
sourceNameBase_ = Util::File::FileNameBase(srcAbsPath) ;
return true;
}
void Option::GetVersion(uint32_t &minor, uint32_t &major)
{
minor = HCS_COMPILER_VERSION_MINOR;
major = HCS_COMPILER_VERSION_MAJOR;
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_OPTION_H
#define HC_GEN_OPTION_H
#include <memory>
#include <string>
namespace OHOS {
namespace Hardware {
class Option {
public:
Option() = default;
~Option() = default;
static Option &Instance();
Option &Parse(int argc, char *argv[]);
void ShowUsage();
void ShowVersion();
bool ShouldShowUsage() const;
bool OptionError() const;
bool ShouldShowVersion() const;
bool ShouldAlign() const;
bool ShouldGenTextConfig() const;
bool ShouldGenBinaryConfig() const;
bool ShouldGenHexDump() const;
bool ShouldDecompile() const;
std::string GetSymbolPrefix();
std::string GetSourceName();
std::string GetSourceNameBase();
std::string GetOutputName();
void GetVersion(uint32_t &minor, uint32_t &major);
bool VerboseLog() const;
std::string GetSourceDir();
static std::string RealPathSourcePath(const char *path);
private:
static void ShowOption(const std::string &option, const std::string &helpInfo);
bool ParseOptions(int argc, char *argv[]);
void SetOptionError(bool shouldShowUsage = true);
bool SetSourceOption(const char* srcName);
bool showUsage_ = false;
bool showVersion_ = false;
bool shouldAlign_ = false;
bool shouldGenTextConfig_ = false;
bool shouldGenByteCodeConfig_ = true;
bool showGenHexDump_ = false;
bool shouldDecompile_ = false;
bool verboseLog_ = false;
bool optionError_ = false;
std::string symbolNamePrefix_;
std::string sourceName_;
std::string sourceNameBase_;
std::string outputName_;
std::string sourceDir_;
};
} // Hardware
} // OHOS
#endif // HC_GEN_OPTION_H
+409
View File
@@ -0,0 +1,409 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "parser.h"
#include <memory>
#include "file.h"
#include "logger.h"
using namespace OHOS::Hardware;
bool Parser::Parse()
{
srcQueue_.push_back(Option::Instance().GetSourceName());
std::list<std::shared_ptr<Ast>> astList;
while (!srcQueue_.empty()) {
std::list<std::string> includeList;
auto oneAst = ParseOne(srcQueue_.front(), includeList);
if (oneAst == nullptr) {
return false;
}
astList.push_back(oneAst);
srcQueue_.pop_front();
srcQueue_.splice(srcQueue_.begin(), includeList);
}
astList.push_back(astList.front());
astList.pop_front();
ast_ = astList.front();
astList.pop_front();
if (!ast_->Merge(astList)) {
Logger().Debug() << "failed to merge ast";
return false;
}
if (!astList.empty()) {
ast_->Dump("merged");
}
if (ast_->GetAstRoot() == nullptr) {
Logger().Error() << Option::Instance().GetSourceName() << ": Empty hcs file";
return false;
}
if (!ast_->Expand()) {
return false;
}
return true;
}
std::shared_ptr<Ast> Parser::ParseOne(const std::string &src, std::list<std::string> &includeList)
{
if (!lexer_.Initialize(src)) {
return nullptr;
}
if (!lexer_.Lex(current_)) {
return nullptr;
}
if (current_ == INCLUDE && !ProcessInclude(includeList)) {
return nullptr;
}
std::shared_ptr<AstObject> rootNode = nullptr;
if (current_ == ROOT) {
auto preToken = current_;
preToken.type = LITERAL;
preToken.strval = "root";
rootNode = ParseNode(preToken);
if (rootNode == nullptr) {
return nullptr;
}
} else if (current_ != EOF) {
Logger().Error() << lexer_ << "syntax error, expect root node of end of file";
return nullptr;
}
if (!lexer_.Lex(current_) || current_ != EOF) {
Logger().Error() << lexer_ << "syntax error, expect EOF";
return nullptr;
}
std::shared_ptr<Ast> oneAst = std::make_shared<Ast>(rootNode);
oneAst->Dump(*lexer_.GetSourceName());
return oneAst;
}
bool Parser::ProcessInclude(std::list<std::string> &includeList)
{
do {
if (!lexer_.Lex(current_) || current_ != STRING) {
Logger().Error() << lexer_ << "syntax error, expect include path after #include";
return false;
}
auto includePath = current_.strval;
if (includePath.empty()) {
Logger().Error() << lexer_ << "include invalid file: \'" << includePath << '\'';
return false;
}
if (includePath[0] != '/') {
auto currentSrc = srcQueue_.front();
auto currentSrcDir = Util::File::GetDir(currentSrc);
includePath = currentSrcDir.append(includePath);
}
auto includeAbsPath = Util::File::AbsPath(includePath);
if (includeAbsPath.empty()) {
Logger().Error() << lexer_ << "include invalid file: \'" << current_.strval << '\'';
return false;
}
includeList.push_back(includeAbsPath);
if (!lexer_.Lex(current_)) {
return false;
}
if (current_ == INCLUDE) {
continue;
}
break;
} while (true);
return true;
}
std::shared_ptr<AstObject> Parser::ParseNode(Token &name, bool bracesStart)
{
/* bracesStart if true, current is '{' , else need to read next token and check with '}' */
if (!bracesStart) {
if (!lexer_.Lex(current_) || current_ != '{') {
Logger().Error() << lexer_ << "syntax error, node miss '{'";
return nullptr;
}
}
auto node = std::shared_ptr<AstObject>(new ConfigNode(name, NODE_NOREF, ""));
std::shared_ptr<AstObject> child;
while (lexer_.Lex(current_) && current_ != '}') {
switch (current_.type) {
case TEMPLATE:
child = ParseTemplate();
break;
case LITERAL:
child = ParseNodeAndTerm();
break;
default:
Logger().Error() << lexer_
<< "syntax error, except '}' or TEMPLATE or LITERAL for node '" << name.strval << '\'';
return nullptr;
}
if (child == nullptr) {
return nullptr;
}
node->AddChild(child);
}
if (current_ != '}') {
Logger().Error() << lexer_ << "syntax error, node miss '}'";
return nullptr;
}
return std::shared_ptr<AstObject>(node);
}
std::shared_ptr<AstObject> Parser::ParseTerm(Token &name)
{
if (!lexer_.Lex(current_)) {
Logger().Error() << lexer_ << "syntax error, miss value of config term";
return nullptr;
}
auto term = std::shared_ptr<AstObject>(new(std::nothrow) ConfigTerm(name, nullptr));
if (term == nullptr) {
return nullptr;
}
switch (current_.type) {
case STRING:
term->AddChild(std::make_shared<AstObject>("", PARSEROP_STRING, current_.strval, current_));
break;
case NUMBER:
term->AddChild(std::make_shared<AstObject>("", PARSEROP_UINT64, current_.numval, current_));
break;
case '[': {
std::shared_ptr<AstObject> list = ParseArray();
if (list == nullptr) {
return nullptr;
} else {
term->AddChild(list);
}
break;
}
case '&':
if (!lexer_.Lex(current_) || (current_ != LITERAL && current_ != REF_PATH)) {
Logger().Error() << lexer_ << "syntax error, invalid config term definition";
return nullptr;
}
term->AddChild(std::make_shared<AstObject>("", PARSEROP_NODEREF, current_.strval, current_));
break;
case DELETE:
term->AddChild(std::make_shared<AstObject>("", PARSEROP_DELETE, current_.strval, current_));
break;
default:
Logger().Error() << lexer_ << "syntax error, invalid config term definition";
return nullptr;
}
if (!lexer_.Lex(current_) || current_ != ';') {
Logger().Error() << lexer_ << "syntax error, miss ';'";
return nullptr;
}
return std::shared_ptr<AstObject>(term);
}
std::shared_ptr<AstObject> Parser::ParseTemplate()
{
if (!lexer_.Lex(current_) || current_ != LITERAL) {
Logger().Error() << lexer_ << "syntax error, template miss name";
return nullptr;
}
auto name = current_;
auto node = ParseNode(name, false);
if (node == nullptr) {
return node;
}
ConfigNode::CastFrom(node)->SetNodeType(NODE_TEMPLATE);
return node;
}
std::shared_ptr<AstObject> Parser::ParseNodeAndTerm()
{
auto name = current_;
if (!lexer_.Lex(current_)) {
Logger().Error() << lexer_ << "syntax error, broken term or node";
return nullptr;
}
switch (current_.type) {
case '=':
return ParseTerm(name);
case '{':
return ParseNode(name, true);
case ':':
if (lexer_.Lex(current_)) {
return ParseNodeWithRef(name);
}
Logger().Error() << lexer_ << "syntax error, unknown node reference type";
break;
default:
Logger().Error() << lexer_ << "syntax error, except '=' or '{' or ':'";
break;
}
return nullptr;
}
std::shared_ptr<AstObject> Parser::ParseNodeWithRef(Token name)
{
std::shared_ptr<AstObject> node;
switch (current_.type) {
case REF_PATH:
case LITERAL:
return ParseNodeCopy(name);
case '&':
return ParseNodeRef(name);
case DELETE:
return ParseNodeDelete(name);
case ':':
return ParseNodeInherit(name);
default:
Logger().Error() << lexer_ << "syntax error, unknown node type";
break;
}
return node;
}
/* started with NodePath on gramme : LITERAL ':' NodePath '{' ConfigTermList '}'*/
std::shared_ptr<AstObject> Parser::ParseNodeCopy(Token &name)
{
auto nodePath = current_.strval;
auto node = ParseNode(name);
if (node == nullptr) {
return nullptr;
}
auto nodeCopy = ConfigNode::CastFrom(node);
nodeCopy->SetNodeType(NODE_COPY);
nodeCopy->SetRefPath(nodePath);
return node;
}
/* started with & on gramme : LITERAL ':' '&' NodePath '{' ConfigTermList '}'*/
std::shared_ptr<AstObject> Parser::ParseNodeRef(Token &name)
{
if (!lexer_.Lex(current_) || (current_ != LITERAL && current_ != REF_PATH)) {
Logger().Error() << lexer_ << "syntax error, miss node reference path";
return nullptr;
}
auto refPath = current_.strval;
auto node = ParseNode(name);
if (node == nullptr) {
return nullptr;
}
auto configNode = ConfigNode::CastFrom(node);
configNode->SetNodeType(NODE_REF);
configNode->SetRefPath(refPath);
return node;
}
/* started with DELETE on gramme : LITERAL ':' DELETE '{' ConfigTermList '}'*/
std::shared_ptr<AstObject> Parser::ParseNodeDelete(Token &name)
{
auto node = ParseNode(name);
if (node == nullptr) {
return nullptr;
}
/* maybe drop node context is better */
auto configNode = ConfigNode::CastFrom(node);
configNode->SetNodeType(NODE_DELETE);
return node;
}
/* started with 2th ':' on gramme : LITERAL ':' ':' NodePath '{' ConfigTermList '}'*/
std::shared_ptr<AstObject> Parser::ParseNodeInherit(Token &name)
{
if (!lexer_.Lex(current_) || (current_ != LITERAL && current_ != REF_PATH)) {
Logger().Error() << lexer_ << "syntax error, miss node inherit path";
return nullptr;
}
auto inheritPath = current_.strval;
auto node = ParseNode(name);
if (node == nullptr) {
return nullptr;
}
auto configNode = ConfigNode::CastFrom(node);
configNode->SetNodeType(NODE_INHERIT);
configNode->SetRefPath(inheritPath);
return node;
}
std::shared_ptr<AstObject> Parser::ParseArray()
{
auto array = std::shared_ptr<AstObject>(new ConfigArray(current_));
int32_t arrayType = 0;
while (lexer_.Lex(current_) && current_ != ']') {
if (current_.type == STRING) {
array->AddChild(std::make_shared<AstObject>("", PARSEROP_STRING, current_.strval, current_));
} else if (current_.type == NUMBER) {
array->AddChild(std::make_shared<AstObject>("", PARSEROP_UINT64, current_.numval, current_));
} else {
Logger().Error() << lexer_ << "syntax error, except STRING or NUMBER in array";
return nullptr;
}
if (arrayType == 0) {
arrayType = current_.type;
} else if (arrayType != current_.type) {
Logger().Error() << lexer_ << "syntax error, not allow mix type array";
return nullptr;
}
if (lexer_.Lex(current_)) {
if (current_ == ',') {
continue;
} else if (current_ == ']') {
break;
} else {
Logger().Error() << lexer_ << "syntax error, except ',' or ']'";
return nullptr;
}
}
return std::shared_ptr<AstObject>();
}
if (current_ != ']') {
Logger().Error() << lexer_ << "syntax error, miss ']' at end of array";
return nullptr;
}
return std::shared_ptr<AstObject>(array);
}
std::shared_ptr<Ast> Parser::GetAst()
{
return ast_;
}
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_PARSER_H
#define HC_GEN_PARSER_H
#include <memory>
#include "ast.h"
#include "lexer.h"
namespace OHOS {
namespace Hardware {
class Parser {
public:
Parser() = default;
~Parser() = default;
bool Parse();
std::shared_ptr<Ast> ParseOne(const std::string &src, std::list<std::string> &includeList);
std::shared_ptr<Ast> GetAst();
private:
bool ProcessInclude(std::list<std::string> &includeList);
std::shared_ptr<AstObject> ParseTemplate();
std::shared_ptr<AstObject> ParseNodeAndTerm();
std::shared_ptr<AstObject> ParseNodeCopy(Token &name);
std::shared_ptr<AstObject> ParseNodeRef(Token &name);
std::shared_ptr<AstObject> ParseNodeDelete(Token &name);
std::shared_ptr<AstObject> ParseNodeInherit(Token &name);
std::shared_ptr<AstObject> ParseNode(Token &name, bool bracesStart = false);
std::shared_ptr<AstObject> ParseTerm(Token &name);
std::shared_ptr<AstObject> ParseNodeWithRef(Token name);
std::shared_ptr<AstObject> ParseArray();
Lexer lexer_;
Token current_;
std::shared_ptr<Ast> ast_;
std::list<std::string> srcQueue_;
};
} // OHOS
} // Hardware
#endif // HC_GEN_PARSER_H
+735
View File
@@ -0,0 +1,735 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include <set>
#include "file.h"
#include "logger.h"
#include "opcode.h"
#include "text_gen.h"
using namespace OHOS::Hardware;
constexpr static const char *FILE_HEAD_COMMENT = \
"/*\n" \
" * This is an automatically generated HDF config file. Do not modify it manually.\n" \
" */\n\n";
TextGen::TextGen(std::shared_ptr<Ast> ast) : Generator(ast)
{
}
bool TextGen::Output()
{
if (!Initialize() || !DuplicateNodeNameCheck()) {
return false;
}
auto ret = HeaderOutput();
if (ret) {
ret = ImplOutput();
}
if (!ret && (ofs_.is_open() && !ofs_.good())) {
Logger().Error() << "failed to write file:" << outputFileName_;
}
return ret;
}
bool TextGen::Initialize()
{
auto opt = Option::Instance();
prefix_ = opt.GetSymbolPrefix();
if (prefix_.empty()) {
prefix_ = "HdfConfig";
}
prefix_ = ToLowerCamelString(prefix_);
auto moduleTerm = ast_->GetAstRoot()->Lookup("module", PARSEROP_CONFTERM);
if (moduleTerm == nullptr) {
return false; // never hit
}
moduleName_ = ToUpperCamelString(moduleTerm->Child()->StringValue());
rootVariableName_ = "g_" + prefix_ + moduleName_ + "ModuleRoot";
return true;
}
bool TextGen::HeaderOutput()
{
if (!InitOutput(".h")) {
return false;
}
ofs_ << FILE_HEAD_COMMENT;
std::string headerMacro = GetHeaderProtectMacro(outputFileName_);
ofs_ << "#ifndef " << headerMacro << "\n";
ofs_ << "#define " << headerMacro << "\n\n";
ofs_ << "#include <stdint.h>\n\n";
if (!HeaderOutputTraversal()) {
return false;
}
ofs_ << "\n#endif // " << headerMacro << '\n';
return ofs_.good();
}
bool TextGen::HeaderOutputTraversal()
{
auto ret = ast_->WalkBackward([this](const std::shared_ptr<AstObject> &current, uint32_t) -> uint32_t {
if (!current->IsNode()) {
return NOERR;
}
auto node = ConfigNode::CastFrom(current);
if (node->GetNodeType() == NODE_INHERIT) {
return NOERR;
}
return GenNodeDefinition(current);
});
if (!ret) {
return false;
}
ofs_ << "const struct " << ToUpperCamelString(prefix_) << moduleName_ << "Root* HdfGet"
<< moduleName_ << "ModuleConfigRoot(void);\n";
return ofs_.good();
}
bool TextGen::ImplOutput()
{
if (!InitOutput(".c")) {
return false;
}
symMap.clear();
ofs_ << FILE_HEAD_COMMENT;
ofs_ << "#include \"" << outputNameBase_ << ".h\"\n\n";
bool ret = OutputTemplateImpl();
if (ret) {
ret = OutputImplGlobalVariables();
}
if (!ret) {
return ret;
}
ofs_ << "\nconst struct " << ToUpperCamelString(prefix_) << moduleName_ << "Root* HdfGet" << moduleName_ << "ModuleConfigRoot(void)\n"
<< "{\n"
<< Indent() << "return &" << rootVariableName_ << ";\n"
<< "}\n";
return ofs_.good();
}
std::string TextGen::ToUpperCamelString(const std::string &str)
{
if (str.empty()) {
return str;
}
auto out = ToCamelString(str);
out[0] = static_cast<char>(toupper(out[0]));
return out;
}
std::string TextGen::ToLowerCamelString(const std::string &str)
{
if (str.empty()) {
return str;
}
auto out = ToCamelString(str);
out[0] = static_cast<char>(tolower(out[0]));
return out;
}
std::string TextGen::ToCamelString(const std::string &str)
{
if (str.empty()) {
return str;
}
if (str.find('_') == std::string::npos) {
return str;
}
std::string out;
char cb = '\0';
constexpr char underLine = '_';
for (auto c : str) {
if (c == '_') {
cb = c;
continue;
}
if (cb == underLine) {
out.push_back(static_cast<char>(toupper(c)));
} else {
out.push_back(c);
}
cb = c;
}
return out;
}
bool TextGen::InitOutput(const std::string &fileSuffix)
{
ofs_.close();
outputFileName_ = Option::Instance().GetOutputName();
if (outputFileName_.empty()) {
outputFileName_ = Option::Instance().GetSourceNameBase();
}
outputFileName_ = Util::File::StripSuffix(outputFileName_).append(fileSuffix);
outputNameBase_ = Util::File::FileNameBase(outputFileName_);
ofs_.open(outputFileName_, std::ostream::out | std::ostream::binary);
if (!ofs_.is_open()) {
Logger().Error() << "failed to open output file: " << outputFileName_;
return false;
}
return true;
}
const std::string &TextGen::ToUpperString(std::string &str)
{
for (char &i : str) {
i = static_cast<char>(toupper(i));
}
return str;
}
std::string TextGen::GetHeaderProtectMacro(const std::string &headerFileName)
{
return std::string().append("HCS_CONFIG_").append(ToUpperString(outputNameBase_)).append("_HEADER_H");
}
uint32_t TextGen::GenNodeDefinition(const std::shared_ptr<AstObject> &node)
{
auto structName = GenConfigStructName(node);
static std::set<std::string> symbolSet;
if (symbolSet.find(structName) != symbolSet.end()) {
return NOERR;
} else {
symbolSet.insert(structName);
}
ofs_ << "struct " << structName << " {\n";
auto termIt = node->Child();
while (termIt != nullptr) {
bool res = GenObjectDefinitionGen(termIt);
if (!res) {
return res;
}
termIt = termIt->Next();
}
ofs_ << "};\n\n";
return ofs_.good() ? NOERR : EOUTPUT;
}
std::string TextGen::GenConfigStructName(const std::shared_ptr<AstObject> &node)
{
return ToUpperCamelString(prefix_).append(ToUpperCamelString(moduleName_)).append(ToUpperCamelString(node->Name()));
}
bool TextGen::GenObjectDefinitionGen(const std::shared_ptr<AstObject>& object)
{
if (!object->IsNode() && !object->IsTerm()) {
return true;
}
switch (object->Type()) {
case PARSEROP_CONFNODE: {
auto structName = GenConfigStructName(object);
auto node = ConfigNode::CastFrom(object);
auto nodeName = ToLowerCamelString(node->Name());
if (node->GetNodeType() == NODE_TEMPLATE) {
ofs_ << Indent() << "const struct " << structName << "* " << nodeName << ";\n";
ofs_ << Indent() << "uint16_t " << nodeName << "Size;\n";
} else if (node->GetNodeType() == NODE_INHERIT) {
return true;
} else {
ofs_ << Indent() << "struct " << structName << " " << nodeName << ";\n";
}
break;
}
case PARSEROP_CONFTERM:
return GenTermDefinition(object);
default:
break;
}
return ofs_.good();
}
bool TextGen::GenTermDefinition(const std::shared_ptr<AstObject> &term)
{
auto value = term->Child();
switch (value->Type()) {
case PARSEROP_ARRAY: {
auto array = ConfigArray::CastFrom(value);
if (IsInTemplate(term)) {
ofs_ << TAB << "const " << TypeToStr(array->ArrayType()) << "* " << term->Name() << ";\n";
ofs_ << TAB << "uint32_t " << term->Name() << "Size;\n";
} else {
ofs_ << TAB << TypeToStr(array->ArrayType()) << " " << term->Name() << "["
<< array->ArraySize() << "];\n";
}
break;
}
case PARSEROP_UINT8:
case PARSEROP_UINT16:
case PARSEROP_UINT32:
case PARSEROP_UINT64:
case PARSEROP_STRING:
ofs_ << TAB << TypeToStr(value->Type()) << " " << term->Name() << ";\n";
break;
case PARSEROP_NODEREF: {
auto structName = GenConfigStructName(ConfigTerm::CastFrom(term)->RefNode().lock());
ofs_ << TAB << "const struct " << structName << "* " << term->Name() << ";\n";
}
break;
default:
break;
}
return ofs_.good();
}
bool TextGen::IsInTemplate(const std::shared_ptr<AstObject> &object)
{
auto p = object->Parent();
while (p != nullptr) {
if (p->IsNode() && ConfigNode::CastFrom(p)->GetNodeType() == NODE_TEMPLATE) {
return true;
}
p = p->Parent();
}
return false;
}
const std::string &TextGen::TypeToStr(uint32_t type)
{
static std::map<uint32_t, std::string> typeMap = {
{PARSEROP_UINT8, "uint8_t"},
{PARSEROP_UINT16, "uint16_t"},
{PARSEROP_UINT32, "uint32_t"},
{PARSEROP_UINT64, "uint64_t"},
{PARSEROP_STRING, "const char*"},
};
return typeMap[type];
}
bool TextGen::OutputImplGlobalVariables()
{
auto forwardWalkFunc = [this](const std::shared_ptr<AstObject>& current, uint32_t depth) -> uint32_t {
return ImplementGenTraversal(current, depth);
};
auto backwardWalkFunc = [this](const std::shared_ptr<AstObject>& current, uint32_t depth) -> uint32_t {
return ImplementCloseBraceGen(current, depth);
};
return ast_->WalkRound(forwardWalkFunc, backwardWalkFunc);
}
const std::string &TextGen::Indent(uint32_t times)
{
static std::map<uint32_t, std::string> indentMap;
auto indent = indentMap.find(times);
if (indent == indentMap.end()) {
auto str = std::string();
for (uint32_t i = 0; i < times; ++i) {
str.append(TAB);
}
indentMap.emplace(std::pair<uint32_t, std::string>(times, std::move(str)));
}
return indentMap.at(times);
}
uint32_t TextGen::ImplementCloseBraceGen(const std::shared_ptr<AstObject> &object, uint32_t depth)
{
if (!object->IsNode() || ConfigNode::CastFrom(object)->GetNodeType() == NODE_INHERIT) {
return NOERR;
}
if (object == ast_->GetAstRoot()) {
ofs_ << "};\n";
} else {
ofs_ << Indent(depth) << "},\n";
}
return ofs_.good() ? NOERR : EOUTPUT;
}
uint32_t TextGen::ImplementGenTraversal(const std::shared_ptr<AstObject> &object, uint32_t depth)
{
if (!object->IsNode() && !object->IsTerm()) {
return NOERR;
}
if (object->IsTerm() && IsInSubClassNode(object)) {
return NOERR;
}
if (object == ast_->GetAstRoot()) {
auto structName = GenConfigStructName(object);
ofs_ << "static const struct " << structName << " " << rootVariableName_ << " = {\n";
if (object->Child() == nullptr) {
ofs_ << "};\n";
}
return ofs_.good() ? NOERR : EOUTPUT;
}
return ObjectImplementGen(object, depth);
}
bool TextGen::IsInSubClassNode(const std::shared_ptr<AstObject> &object)
{
std::shared_ptr<AstObject> obj = object;
while (obj != nullptr) {
if (obj->IsNode() && ConfigNode::CastFrom(obj)->GetNodeType() == NODE_INHERIT) {
return true;
}
obj = obj->Parent();
}
return false;
}
uint32_t TextGen::ObjectImplementGen(const std::shared_ptr<AstObject> &object, uint32_t depth)
{
switch (object->Type()) {
case PARSEROP_CONFNODE: {
auto node = ConfigNode::CastFrom(object);
if (node->GetNodeType() != NODE_NOREF) {
return TemplateObjectImplGen(object, depth) ? EASTWALKBREAK : EOUTPUT;
}
ofs_ << Indent(depth) << '.' << node->Name() << " = {\n";
if (node->Child() == nullptr) {
ofs_ << Indent(depth) << "},\n";
}
break;
}
case PARSEROP_CONFTERM:
return PrintTermImplement(object, depth);
default:
return NOERR;
}
return ofs_.good() ? NOERR : EOUTPUT;
}
bool TextGen::TemplateObjectImplGen(const std::shared_ptr<AstObject> &object, uint32_t depth)
{
auto node = ConfigNode::CastFrom(object);
if (node->GetNodeType() != NODE_TEMPLATE) {
return true;
}
std::string varName = GenTemplateVariableName(object);
auto nodeName = ToLowerCamelString(node->Name());
ofs_ << Indent(depth) << '.' << nodeName << " = ";
if (node->InheritCount() != 0) {
ofs_ << varName;
} else {
ofs_ << '0';
}
ofs_ << ",\n";
ofs_ << Indent(depth) << '.' << nodeName << "Size = " << node->InheritCount() << ",\n";
return ofs_.good();
}
std::string TextGen::GenTemplateVariableName(const std::shared_ptr<AstObject> &object)
{
auto name = ToUpperCamelString(object->Name());
auto sym = SymbolFind(name);
auto node = ConfigNode::CastFrom(object);
if (sym == nullptr) {
SymbolAdd(name, object);
} else if (sym->object != object && node->TemplateSignNum() == 0) {
sym->duplicateCount++;
node->SetTemplateSignNum(sym->duplicateCount);
}
return node->TemplateSignNum() != 0 ?
std::string("g_").append(prefix_).append(name).append(std::to_string(node->TemplateSignNum())) :
std::string("g_").append(prefix_).append(name);
}
std::shared_ptr<TextGen::Symbol> TextGen::SymbolFind(const std::string &name)
{
auto sym = symMap.find(name);
return sym == symMap.end() ? nullptr : sym->second;
}
void TextGen::SymbolAdd(const std::string &name, const std::shared_ptr<AstObject> &object)
{
auto sym = symMap.find(name);
if (sym != symMap.end()) {
sym->second->duplicateCount++;
}
symMap.insert(std::make_pair(std::string(name), std::make_shared<Symbol>(object, 1)));
}
uint32_t TextGen::PrintTermImplement(const std::shared_ptr<AstObject> &object, uint32_t depth)
{
auto term = ConfigTerm::CastFrom(object);
auto value = object->Child();
switch (value->Type()) {
case PARSEROP_UINT8:
case PARSEROP_UINT16: /* fall-through */
case PARSEROP_UINT32: /* fall-through */
case PARSEROP_UINT64: /* fall-through */
case PARSEROP_STRING:
ofs_ << Indent(depth) << '.' << term->Name() << " = ";
if (!PrintBaseTypeValue(value)) {
return EOUTPUT;
}
ofs_ << ",\n";
break;
case PARSEROP_ARRAY:
return PrintArrayImplement(object, depth);
case PARSEROP_NODEREF: {
std::string refPath = HcsBuildObjectPath(term->RefNode().lock());
ofs_ << Indent(depth) << '.' << term->Name() << " = &" << refPath << ",\n";
break;
}
default:
break;
}
return ofs_.good() ? NOERR : EOUTPUT;
}
bool TextGen::PrintBaseTypeValue(const std::shared_ptr<AstObject> &object)
{
switch (object->Type()) {
case PARSEROP_UINT8: /* fallthrough */
case PARSEROP_UINT16: /* fallthrough */
case PARSEROP_UINT32: /* fallthrough */
case PARSEROP_UINT64:
ofs_ << "0x" << std::hex << object->IntegerValue();
break;
case PARSEROP_STRING:
ofs_ << '"' << object->StringValue() << '"';
break;
default:
break;
}
return ofs_.good();
}
uint32_t TextGen::PrintArrayImplement(const std::shared_ptr<AstObject> &object, uint32_t depth)
{
if (IsInSubClassNode(object)) {
return PrintArrayImplInSubClass(object, depth) ? NOERR : EOUTPUT;
}
auto termContext = object->Child();
ofs_ << Indent(depth) << '.' << object->Name() << " = { ";
if (!HcsPrintArrayContent(termContext, depth + 1)) {
return EOUTPUT;
}
ofs_ << " },\n";
return ofs_.good() ? NOERR : EOUTPUT;
}
bool TextGen::PrintArrayImplInSubClass(const std::shared_ptr<AstObject> &object, uint32_t depth)
{
auto array = ConfigArray::CastFrom(object->Child());
auto arrayName = GenArrayName(object);
ofs_ << Indent(depth) << '.' << object->Name() << " = " << arrayName << ",\n";
ofs_ << Indent(depth) << '.' << object->Name() << "Size = " << std::to_string(array->ArraySize()) << ",\n";
return ofs_.good();
}
bool TextGen::HcsPrintArrayContent(const std::shared_ptr<AstObject> &object, uint32_t indent)
{
constexpr uint32_t ELEMENT_PER_LINE = 16;
auto element = object->Child();
uint32_t elementCount = 0;
while (element != nullptr) {
if (!PrintBaseTypeValue(element)) {
return false;
}
if (elementCount++ >= ELEMENT_PER_LINE) {
ofs_ << "\n" << Indent(indent);
}
element = element->Next();
if (element != nullptr) {
ofs_ << ", ";
}
}
return ofs_.good();
}
std::string TextGen::HcsBuildObjectPath(std::shared_ptr<AstObject> object)
{
std::list<std::shared_ptr<AstObject>> pathList;
auto p = object;
while (p != ast_->GetAstRoot()) {
pathList.push_back(p);
p = p->Parent();
}
pathList.reverse();
std::string path = rootVariableName_;
for (auto &it : pathList) {
path.append(".").append(it->Name());
}
return path;
}
bool TextGen::OutputTemplateImpl()
{
if (!OutputTemplateVariablesDeclare()) {
return false;
}
return ast_->WalkBackward([this](const std::shared_ptr<AstObject> &object, uint32_t) -> uint32_t {
if (!object->IsNode() ||
(object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() != NODE_TEMPLATE)) {
return NOERR;
}
auto node = ConfigNode::CastFrom(object);
if (node->InheritCount() == 0) {
return NOERR;
}
ofs_ << "static const struct " << GenConfigStructName(object) << ' '
<< GenTemplateVariableName(object) << "[] = {\n";
auto subClass = node->SubClasses();
for (auto nodeObj : subClass) {
std::shared_ptr<AstObject> obj = std::shared_ptr<AstObject>(nodeObj, [](auto p) {});
ofs_ << Indent() << '[' << ConfigNode::CastFrom(obj)->InheritIndex() << "] = {\n";
if (!TemplateVariableGen(obj)) {
return EOUTPUT;
}
ofs_ << Indent() << "},\n";
}
ofs_ << "};\n\n";
return ofs_.good() ? NOERR : EOUTPUT;
});
}
bool TextGen::OutputTemplateVariablesDeclare()
{
return ast_->WalkBackward([this](const std::shared_ptr<AstObject> &object, uint32_t) -> uint32_t {
if (object->IsTerm() && object->Child()->IsArray()) {
return ArrayVariablesDeclareGen(object);
} else if (!object->IsNode() ||
(object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() != NODE_TEMPLATE)) {
return NOERR;
}
auto node = ConfigNode::CastFrom(object);
if (node->InheritCount() == 0) {
return NOERR;
}
auto structName = GenConfigStructName(object);
ofs_ << "static const struct " << GenConfigStructName(object) << ' ' << GenTemplateVariableName(object)
<< "[];\n\n";
return ofs_.good() ? NOERR : EOUTPUT;
});
}
uint32_t TextGen::ArrayVariablesDeclareGen(const std::shared_ptr<AstObject> &object)
{
if (!IsInSubClassNode(object)) {
return NOERR;
}
auto arrayName = GenArrayName(object);
auto array = ConfigArray::CastFrom(object->Child());
ofs_ << "static const " << TypeToStr(array->ArrayType()) << ' ' << arrayName << '[' << array->ArraySize()
<< "] = {\n" << Indent();
HcsPrintArrayContent(object->Child(), 1);
ofs_ << "\n};\n\n";
return ofs_.good() ? NOERR : EOUTPUT;
}
std::string TextGen::GenArrayName(const std::shared_ptr<AstObject> &term)
{
auto arrayName = std::string("g_hcsConfigArray").append(ToUpperCamelString(term->Name()));
auto t = ConfigTerm::CastFrom(term);
auto sym = SymbolFind(arrayName);
if (sym == nullptr) {
SymbolAdd(arrayName, term);
t->SetSigNum(1);
} else if (t->SigNum() == 0){
t->SetSigNum(sym->duplicateCount + 1);
sym->duplicateCount++;
}
arrayName.append(std::to_string(t->SigNum()));
return arrayName;
}
uint32_t TextGen::TemplateVariableGen(const std::shared_ptr<AstObject> &nodeObject)
{
auto child = nodeObject->Child();
while (child != nullptr) {
auto res = Ast::WalkRound(child,
[this](const std::shared_ptr<AstObject>& object, uint32_t depth) -> uint32_t {
return ObjectImplementGen(object, depth + 2);
},
[this](const std::shared_ptr<AstObject>& object, uint32_t depth) -> uint32_t {
return ImplementCloseBraceGen(object, depth + 2);
});
if (!res) {
return false;
}
child = child->Next();
}
return true;
}
bool TextGen::DuplicateNodeNameCheck()
{
std::map<std::string, std::shared_ptr<AstObject>> nodeMap;
return ast_->WalkForward([&](const std::shared_ptr<AstObject>& current, uint32_t) -> uint32_t {
if (!current->IsNode() || IsInSubClassNode(current)) {
return NOERR;
}
auto node = nodeMap.find(current->Name());
if (node == nodeMap.end()) {
nodeMap[current->Name()] = current;
return NOERR;
}
Logger().Error() << current->SourceInfo() << "duplicate node name at " << node->second->SourceInfo() << "\n"
<< "To avoid redefining structures, not allow duplicate node name at text config mode";
return EFAIL;
});
}
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_TEXT_GENERATOR_H
#define HC_GEN_TEXT_GENERATOR_H
#include <fstream>
#include <map>
#include <utility>
#include "generator.h"
namespace OHOS {
namespace Hardware {
class TextGen : public Generator {
public:
explicit TextGen(std::shared_ptr<Ast> ast);
~TextGen() override = default;
bool Output() override;
private:
bool Initialize();
bool HeaderOutput();
bool HeaderOutputTraversal();
bool ImplOutput();
bool InitOutput(const std::string &fileSuffix);
bool DuplicateNodeNameCheck();
static std::string ToUpperCamelString(const std::string &str);
static std::string ToLowerCamelString(const std::string &str);
static std::string ToCamelString(const std::string &str);
static const std::string &ToUpperString(std::string &str);
std::string GetHeaderProtectMacro(const std::string &headerFileName);
uint32_t GenNodeDefinition(const std::shared_ptr<AstObject> &node);
std::string GenConfigStructName(const std::shared_ptr<AstObject> &node);
bool GenObjectDefinitionGen(const std::shared_ptr<AstObject>& object);
bool GenTermDefinition(const std::shared_ptr<AstObject> &term);
static const std::string &TypeToStr(uint32_t type);
static bool IsInTemplate(const std::shared_ptr<AstObject> &object);
bool OutputImplGlobalVariables();
uint32_t ImplementGenTraversal(const std::shared_ptr<AstObject> &object, uint32_t depth);
uint32_t ImplementCloseBraceGen(const std::shared_ptr<AstObject> &object, uint32_t depth);
static const std::string & Indent(uint32_t times = 1);
static bool IsInSubClassNode(const std::shared_ptr<AstObject> &object);
uint32_t ObjectImplementGen(const std::shared_ptr<AstObject> &object, uint32_t depth);
bool TemplateObjectImplGen(const std::shared_ptr<AstObject> &object, uint32_t depth);
std::string GenTemplateVariableName(const std::shared_ptr<AstObject> &object);
struct Symbol {
Symbol(std::shared_ptr<AstObject> obj, uint32_t c) : object(std::move(obj)), duplicateCount(c) {};
~Symbol() = default;
std::shared_ptr<AstObject> object;
uint32_t duplicateCount;
};
std::shared_ptr<Symbol> SymbolFind(const std::string &name);
void SymbolAdd(const std::string &name, const std::shared_ptr<AstObject>& object);
std::ofstream ofs_;
std::string outputFileName_;
std::string outputNameBase_;
std::string prefix_;
std::string moduleName_;
std::string rootVariableName_;
std::map<std::string, std::shared_ptr<Symbol>> symMap;
uint32_t PrintTermImplement(const std::shared_ptr<AstObject> &object, uint32_t depth);
bool PrintBaseTypeValue(const std::shared_ptr<AstObject>& object);
uint32_t PrintArrayImplement(const std::shared_ptr<AstObject> &object, uint32_t depth);
bool PrintArrayImplInSubClass(const std::shared_ptr<AstObject> &object, uint32_t depth);
bool HcsPrintArrayContent(const std::shared_ptr<AstObject>& object, uint32_t indent);
std::string HcsBuildObjectPath(std::shared_ptr<AstObject> object);
bool OutputTemplateImpl();
bool OutputTemplateVariablesDeclare();
uint32_t ArrayVariablesDeclareGen(const std::shared_ptr<AstObject>& object);
std::string GenArrayName(const std::shared_ptr<AstObject>& term);
uint32_t TemplateVariableGen(const std::shared_ptr<AstObject>& nodeObject);
};
} // Hardware
} // OHOS
#endif // HC_GEN_TEXT_GENERATOR_H
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "token.h"
#include <iomanip>
#include <map>
using namespace OHOS::Hardware;
std::string OHOS::Hardware::TokenType2String(int32_t type)
{
static std::map<int32_t, std::string> tokenTypeMap = {
{NUMBER, "NUMBER"},
{TEMPLATE, "TEMPLATE"},
{LITERAL, "LITERAL"},
{ROOT, "ROOT"},
{INCLUDE, "INCLUDE"},
{DELETE, "DELETE"},
{STRING, "STRING"},
{REF_PATH, "REF_PATH"},
{FILE_PATH, "FILE_PATH"}
};
std::string str;
if (type < '~') {
str.push_back(static_cast<char>(type));
return str;
} else if (tokenTypeMap.find(type) != tokenTypeMap.end()) {
str = tokenTypeMap[type];
}
return str;
}
std::ostream &OHOS::Hardware::operator<<(std::ostream &stream, const OHOS::Hardware::Token &t)
{
stream << "Token: type: " << std::setw(8) << ::std::left << TokenType2String(t.type).data();
stream << " value: " << std::setw(8) << ::std::left;
t.type != NUMBER ? stream << std::setw(20) << t.strval.data()
: stream << std::setw(0) << "0x" << std::setw(18) << std::hex << t.numval;
stream << " lineno:" << t.lineNo;
return stream;
}
bool Token::operator==(int32_t t) const
{
return t == type;
}
bool Token::operator!=(int32_t t) const
{
return t != type;
}
bool Token::operator==(Token &t) const
{
return t.type == type && t.numval == numval && t.strval == strval;
}
bool Token::operator!=(Token &t) const
{
return t.type != type || t.numval != numval || t.strval != strval;
}
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_TOKEN_H
#define HC_GEN_TOKEN_H
#include <cstdint>
#include <memory>
#include <ostream>
#include <string>
namespace OHOS {
namespace Hardware {
enum TokenType {
NUMBER = 256,
TEMPLATE,
LITERAL,
STRING,
REF_PATH,
FILE_PATH,
ROOT,
INCLUDE,
DELETE,
};
struct Token {
int32_t type;
std::string strval;
uint64_t numval;
std::shared_ptr<std::string> src;
int32_t lineNo;
bool operator==(Token &t) const;
bool operator!=(Token &t) const;
bool operator==(int32_t type) const;
bool operator!=(int32_t type) const;
friend std::ostream &operator<<(std::ostream &stream, const Token &t);
};
std::string TokenType2String(int32_t type);
} // Hardware
} // OHOS
#endif // HC_GEN_TOKEN_H
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef HC_GEN_TYPES_H
#define HC_GEN_TYPES_H
#define ALIGN_SIZE 4
#define TAB " "
#define TAB_SIZE 4
#define OPCODE_BYTE_WIDTH 1
#define BYTE_SIZE 1
#define WORD_SIZE 2
#define DWORD_SIZE 4
#define QWORD_SIZE 8
#define UNIX_SEPARATOR '/'
#define WIN_SEPARATOR '\\'
#ifdef OS_WIN
#define OS_SEPARATOR WIN_SEPARATOR
#else
#define OS_SEPARATOR UNIX_SEPARATOR
#endif
enum HcsErrorNo {
NOERR = 0, /* No error */
EFAIL, /* Process fail */
EOOM, /* Out of memory */
EOPTION, /* Option error */
EREOPENF, /* Reopen argument */
EINVALF, /* Invalid file */
EINVALARG, /* Invalid argument */
EDECOMP, /* Decompile error */
EOUTPUT, /* Output error */
EASTWALKBREAK, /* Break ast walk */
};
#endif // HC_GEN_TYPES_H
View File
@@ -0,0 +1,3 @@
[compile exit status]:1
[compile console output]:
[Error] ./01_empty_file_ei/case.hcs: Empty hcs file
@@ -0,0 +1,3 @@
[compile exit status]:1
[compile console output]:
[Error] ./01_empty_file_ei/case.hcs: Empty hcs file
+3
View File
@@ -0,0 +1,3 @@
root {
}
@@ -0,0 +1,3 @@
[compile exit status]:1
[compile console output]:
[Error] ./02_empty_root_ei/case.hcs:1 miss 'module' attribute under root node
@@ -0,0 +1,3 @@
[compile exit status]:1
[compile console output]:
[Error] ./02_empty_root_ei/case.hcs:1 miss 'module' attribute under root node
+6
View File
@@ -0,0 +1,6 @@
root {
module = "test";
foo {
}
}
@@ -0,0 +1,16 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.foo = {
},
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,9 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
foo {
}
}
@@ -0,0 +1,20 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestFoo {
};
struct HdfConfigTestRoot {
const char* module;
struct HdfConfigTestFoo foo;
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAACEAAAABcm9vdAAXAAAAAm1vZHVsZQAUdGVzdAABZm9vAAAAAAA=
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+9
View File
@@ -0,0 +1,9 @@
root {
module = "test";
term1 = 1;
term2 = 0x2;
term3 = 0b11;
term_uint16 = 0xffff;
term_uint32 = 0xffffffff;
term_uint64 = 0xffffffffff;
}
@@ -0,0 +1,20 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.term1 = 0x1,
.term2 = 0x2,
.term3 = 0x3,
.term_uint16 = 0xffff,
.term_uint32 = 0xffffffff,
.term_uint64 = 0xffffffffff,
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,13 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
term1 = 0x1;
term2 = 0x2;
term3 = 0x3;
term_uint16 = 0xFFFF;
term_uint32 = 0xFFFFFFFF;
term_uint64 = 0xFFFFFFFFFF;
}
@@ -0,0 +1,22 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestRoot {
const char* module;
uint8_t term1;
uint8_t term2;
uint8_t term3;
uint16_t term_uint16;
uint32_t term_uint32;
uint64_t term_uint64;
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAAGsAAAABcm9vdABhAAAAAm1vZHVsZQAUdGVzdAACdGVybTEAEAECdGVybTIAEAICdGVybTMAEAMCdGVybV91aW50MTYAEf//AnRlcm1fdWludDMyABL/////AnRlcm1fdWludDY0ABP//////wAAAA==
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+4
View File
@@ -0,0 +1,4 @@
root {
module = "test";
term1 = "hello";
}
@@ -0,0 +1,15 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.term1 = "hello",
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,8 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
term1 = "hello";
}
@@ -0,0 +1,17 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestRoot {
const char* module;
const char* term1;
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAACYAAAABcm9vdAAcAAAAAm1vZHVsZQAUdGVzdAACdGVybTEAFGhlbGxvAA==
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+4
View File
@@ -0,0 +1,4 @@
root {
module = "test";
term1 = [0x1,0x2,0xffffffffff];
}
@@ -0,0 +1,15 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.term1 = { 0x1, 0x2, 0xffffffffff },
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,8 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
term1 = [0x1, 0x2, 0xFFFFFFFFFF];
}
@@ -0,0 +1,17 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestRoot {
const char* module;
uint64_t term1[3];
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAAC8AAAABcm9vdAAlAAAAAm1vZHVsZQAUdGVzdAACdGVybTEABAMAEAEQAhP//////wAAAA==
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+4
View File
@@ -0,0 +1,4 @@
root {
module = "test";
term1 = ["hello", "world"];
}
@@ -0,0 +1,15 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.term1 = { "hello", "world" },
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,8 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
term1 = ["hello", "world"];
}
@@ -0,0 +1,17 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestRoot {
const char* module;
const char* term1[2];
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAADAAAAABcm9vdAAmAAAAAm1vZHVsZQAUdGVzdAACdGVybTEABAIAFGhlbGxvABR3b3JsZAA=
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+12
View File
@@ -0,0 +1,12 @@
root {
module = "test";
foo {
term1 = 1;
term2 = 0x2;
term3 = 0b11;
}
bar {
term1 = &root.bar;
}
}
@@ -0,0 +1,22 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.foo = {
.term1 = 0x1,
.term2 = 0x2,
.term3 = 0x3,
},
.bar = {
.term1 = &g_hdfConfigTestModuleRoot.bar,
},
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,15 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
foo {
term1 = 0x1;
term2 = 0x2;
term3 = 0x3;
}
bar {
term1 = &root.bar;
}
}
@@ -0,0 +1,28 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestFoo {
uint8_t term1;
uint8_t term2;
uint8_t term3;
};
struct HdfConfigTestBar {
const struct HdfConfigTestBar* term1;
};
struct HdfConfigTestRoot {
const char* module;
struct HdfConfigTestFoo foo;
struct HdfConfigTestBar bar;
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
+1
View File
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAAFEAAAABcm9vdABHAAAAAm1vZHVsZQAUdGVzdAABZm9vABsAAAACdGVybTEAEAECdGVybTIAEAICdGVybTMAEAMBYmFyAAwAAAACdGVybTEAA1AAAAA=
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+11
View File
@@ -0,0 +1,11 @@
root {
module = "test";
foo {
foo1 {
term1 = "hello";
bar {
term1 = "world";
}
}
}
}
@@ -0,0 +1,22 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.foo = {
.foo1 = {
.term1 = "hello",
.bar = {
.term1 = "world",
},
},
},
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,15 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
foo {
foo1 {
term1 = "hello";
bar {
term1 = "world";
}
}
}
}
@@ -0,0 +1,30 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestBar {
const char* term1;
};
struct HdfConfigTestFoo1 {
const char* term1;
struct HdfConfigTestBar bar;
};
struct HdfConfigTestFoo {
struct HdfConfigTestFoo1 foo1;
};
struct HdfConfigTestRoot {
const char* module;
struct HdfConfigTestFoo foo;
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAAFAAAAABcm9vdABGAAAAAm1vZHVsZQAUdGVzdAABZm9vAC8AAAABZm9vMQAlAAAAAnRlcm0xABRoZWxsbwABYmFyAA4AAAACdGVybTEAFHdvcmxkAA==
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+13
View File
@@ -0,0 +1,13 @@
root {
module = "test";
foo {
term1 = 1;
term2 = 0x2;
term3 = 0b11;
}
bar : foo {
term1 = 2;
term4 = "hello";
}
}
@@ -0,0 +1,25 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.foo = {
.term1 = 0x1,
.term2 = 0x2,
.term3 = 0x3,
},
.bar = {
.term1 = 0x2,
.term4 = "hello",
.term2 = 0x2,
.term3 = 0x3,
},
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,18 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
foo {
term1 = 0x1;
term2 = 0x2;
term3 = 0x3;
}
bar {
term1 = 0x2;
term4 = "hello";
term2 = 0x2;
term3 = 0x3;
}
}
@@ -0,0 +1,31 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestFoo {
uint8_t term1;
uint8_t term2;
uint8_t term3;
};
struct HdfConfigTestBar {
uint8_t term1;
const char* term4;
uint8_t term2;
uint8_t term3;
};
struct HdfConfigTestRoot {
const char* module;
struct HdfConfigTestFoo foo;
struct HdfConfigTestBar bar;
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAAG4AAAABcm9vdABkAAAAAm1vZHVsZQAUdGVzdAABZm9vABsAAAACdGVybTEAEAECdGVybTIAEAICdGVybTMAEAMBYmFyACkAAAACdGVybTEAEAICdGVybTQAFGhlbGxvAAJ0ZXJtMgAQAgJ0ZXJtMwAQAw==
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+13
View File
@@ -0,0 +1,13 @@
root {
module = "test";
foo {
term1 = 1;
term2 = 0x2;
term3 = 0b11;
}
bar : &foo {
term1 = 2;
term4 = "world";
}
}
@@ -0,0 +1,20 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#include "golden.h"
static const struct HdfConfigTestRoot g_hdfConfigTestModuleRoot = {
.module = "test",
.foo = {
.term1 = 0x2,
.term2 = 0x2,
.term3 = 0x3,
.term4 = "world",
},
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void)
{
return &g_hdfConfigTestModuleRoot;
}
@@ -0,0 +1,13 @@
/*
* HDF decompile hcs file
*/
root {
module = "test";
foo {
term1 = 0x2;
term2 = 0x2;
term3 = 0x3;
term4 = "world";
}
}
@@ -0,0 +1,24 @@
/*
* This is an automatically generated HDF config file. Do not modify it manually.
*/
#ifndef HCS_CONFIG_GOLDEN_HEADER_H
#define HCS_CONFIG_GOLDEN_HEADER_H
#include <stdint.h>
struct HdfConfigTestFoo {
uint8_t term1;
uint8_t term2;
uint8_t term3;
const char* term4;
};
struct HdfConfigTestRoot {
const char* module;
struct HdfConfigTestFoo foo;
};
const struct HdfConfigTestRoot* HdfGetTestModuleConfigRoot(void);
#endif // HCS_CONFIG_GOLDEN_HEADER_H
@@ -0,0 +1 @@
CqAKoAAAAAAHAAAAAAAAAEoAAAABcm9vdABAAAAAAm1vZHVsZQAUdGVzdAABZm9vACkAAAACdGVybTEAEAICdGVybTIAEAICdGVybTMAEAMCdGVybTQAFHdvcmxkAA==
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
@@ -0,0 +1,2 @@
[compile exit status]:0
[compile console output]:
+8
View File
@@ -0,0 +1,8 @@
root {
module = "test";
foo {
term1 = 1;
term2 = 0x2;
term3 = 0b11;
}
}
+11
View File
@@ -0,0 +1,11 @@
#include "base.hcs"
root {
bar {
term = [0,1];
}
foo {
term1 = 2;
term4 = "world";
}
}

Some files were not shown because too many files have changed in this diff Show More