mirror of
https://github.com/openharmony/drivers_framework.git
synced 2026-08-27 10:51:15 -04:00
@@ -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
@@ -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.
Executable
+72
@@ -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
@@ -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
|
||||
@@ -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> ¤t, 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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> ¤t, int32_t walkDepth) -> int32_t {
|
||||
return OutPutWalk(current, walkDepth);
|
||||
},
|
||||
[this](std::shared_ptr<AstObject> ¤t, int32_t walkDepth) -> int32_t {
|
||||
return CloseBrace(current, walkDepth);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return file_.good();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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> ¤t, 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;
|
||||
});
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Executable
+3
@@ -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
|
||||
Executable
+6
@@ -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]:
|
||||
Executable
+9
@@ -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]:
|
||||
Executable
+4
@@ -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]:
|
||||
Executable
+4
@@ -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]:
|
||||
Executable
+4
@@ -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]:
|
||||
Executable
+12
@@ -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
|
||||
@@ -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]:
|
||||
Executable
+11
@@ -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]:
|
||||
Executable
+13
@@ -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]:
|
||||
Executable
+13
@@ -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]:
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
root {
|
||||
module = "test";
|
||||
foo {
|
||||
term1 = 1;
|
||||
term2 = 0x2;
|
||||
term3 = 0b11;
|
||||
}
|
||||
}
|
||||
Executable
+11
@@ -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
Reference in New Issue
Block a user