mirror of
https://github.com/openharmony/drivers_framework.git
synced 2026-08-27 20:49:55 -04:00
07527c9d69
Signed-off-by: yue <yueyan4@huawei.com>
337 lines
9.5 KiB
C++
Executable File
337 lines
9.5 KiB
C++
Executable File
/*
|
|
* 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/lexer.h"
|
|
#include <utility>
|
|
#include "util/string_builder.h"
|
|
|
|
namespace OHOS {
|
|
namespace HDI {
|
|
Lexer::Lexer()
|
|
{
|
|
InitializeKeywords();
|
|
}
|
|
|
|
Lexer::~Lexer()
|
|
{
|
|
if (currentFile_ != nullptr) {
|
|
currentFile_->Close();
|
|
}
|
|
}
|
|
|
|
void Lexer::InitializeKeywords()
|
|
{
|
|
keywords_ = {
|
|
{ "boolean", Token::BOOLEAN }, { "byte", Token::BYTE }, { "callback", Token::CALLBACK },
|
|
{ "char", Token::CHAR}, { "double", Token::DOUBLE }, { "enum", Token::ENUM },
|
|
{ "extends", Token::EXTENDS }, { "float", Token::FLOAT }, { "full", Token::FULL },
|
|
{ "import", Token::IMPORT }, { "in", Token::IN }, { "int", Token::INTEGER }, { "interface", Token::INTERFACE },
|
|
{ "List", Token::LIST }, { "lite", Token::LITE }, { "long", Token::LONG },
|
|
{ "Map", Token::MAP }, { "oneway", Token::ONEWAY }, { "out", Token::OUT },
|
|
{ "package", Token::PACKAGE}, { "sequenceable", Token::SEQUENCEABLE }, { "short", Token::SHORT },
|
|
{ "String", Token::STRING }, { "struct", Token::STRUCT }, { "union", Token::UNION },
|
|
{ "unsigned", Token::UNSIGNED }, { "FileDescriptor", Token::FILEDESCRIPTOR }
|
|
};
|
|
|
|
delimiters_ = {
|
|
{'<', Token::ANGLE_BRACKETS_LEFT}, {'>', Token::ANGLE_BRACKETS_RIGHT},
|
|
{'{', Token::BRACES_LEFT}, {'}', Token::BRACES_RIGHT},
|
|
{'[', Token::BRACKETS_LEFT}, {']', Token::BRACKETS_RIGHT},
|
|
{',', Token::COMMA}, {'(', Token::PARENTHESES_LEFT},
|
|
{')', Token::PARENTHESES_RIGHT}, {'.', Token::DOT},
|
|
{':', Token::COLON}, {';', Token::SEMICOLON},
|
|
{'=', Token::ASSIGN}
|
|
};
|
|
|
|
tokenDumps_ = {
|
|
{ Token::ANGLE_BRACKETS_LEFT, "<" }, { Token::ANGLE_BRACKETS_RIGHT, ">"}, { Token::BOOLEAN, "boolean"},
|
|
{ Token::BRACES_LEFT, "{"}, { Token::BRACES_RIGHT, "}"}, { Token::BRACKETS_LEFT, "["},
|
|
{ Token::BRACKETS_RIGHT, "]"}, { Token::BYTE, "byte"}, { Token::CALLBACK, "callback"},
|
|
{ Token::CHAR, "char"}, { Token::COLON, ":"}, { Token::COMMA, ","},
|
|
{ Token::DOT, "."}, { Token::DOUBLE, "double"}, { Token::END_OF_FILE, "eof"},
|
|
{ Token::ENUM, "enum"}, { Token::EXTENDS, "extends"}, { Token::FLOAT, "float"},
|
|
{ Token::FULL, "full"}, { Token::IMPORT, "import"}, { Token::IN, "in"},
|
|
{ Token::INTEGER, "int"}, { Token::INTERFACE, "interface"}, { Token::LITE, "lite"},
|
|
{ Token::LIST, "List"}, { Token::LONG, "long"}, { Token::MAP, "Map"},
|
|
{ Token::ONEWAY, "oneway"}, { Token::OUT, "out"}, { Token::PACKAGE, "package"},
|
|
{ Token::SEQUENCEABLE, "sequenceable"}, { Token::STRUCT, "struct"}, { Token::PARENTHESES_LEFT, "("},
|
|
{ Token::PARENTHESES_RIGHT, ")"}, { Token::SEMICOLON, ";"}, { Token::SHORT, "short"},
|
|
{ Token::STRING, "String"}, { Token::UNION, "union"}, { Token::UNSIGNED, "unsigned"},
|
|
{ Token::FILEDESCRIPTOR, "FileDescriptor"}
|
|
};
|
|
}
|
|
|
|
bool Lexer::OpenSourceFile(const String& filePath)
|
|
{
|
|
currentFile_ = std::make_unique<File>(filePath, int(File::READ));
|
|
if (!currentFile_->IsValid()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Token Lexer::GetToken(bool skipComment)
|
|
{
|
|
if (!havePeek_) {
|
|
currentToken_ = ReadToken(skipComment);
|
|
}
|
|
havePeek_ = false;
|
|
return currentToken_;
|
|
}
|
|
|
|
Token Lexer::PeekToken(bool skipComment)
|
|
{
|
|
if (!havePeek_) {
|
|
currentToken_ = ReadToken(skipComment);
|
|
havePeek_ = true;
|
|
}
|
|
return currentToken_;
|
|
}
|
|
|
|
Token Lexer::ReadToken(bool skipComment)
|
|
{
|
|
while (!currentFile_->IsEof()) {
|
|
char c = currentFile_->GetChar();
|
|
tokenLineNo_ = currentFile_->GetCharLineNumber();
|
|
tokenColumnNo_ = currentFile_->GetCharColumnNumber();
|
|
if (IsSpace(c)) {
|
|
continue;
|
|
} else if (IsAlphabet(c) || c == '_') {
|
|
Token t = ReadIdentifier(c);
|
|
return t;
|
|
} else if (IsDecimalDigital(c)) {
|
|
Token t = ReadDecimalDigital(c);
|
|
return t;
|
|
}
|
|
|
|
auto iter = delimiters_.find(c);
|
|
if (iter != delimiters_.end()) {
|
|
return iter->second;
|
|
}
|
|
|
|
if (c == '/') {
|
|
if (currentFile_->PeekChar() == '/') {
|
|
ReadLineComment(c);
|
|
if (!skipComment) {
|
|
return currentToken_;
|
|
}
|
|
continue;
|
|
} else if (currentFile_->PeekChar() == '*') {
|
|
ReadBlockComment(c);
|
|
if (!skipComment) {
|
|
return currentToken_;
|
|
}
|
|
continue;
|
|
}
|
|
currentToken_ = Token::UNKNOWN;
|
|
return currentToken_;
|
|
}
|
|
|
|
currentToken_ = Token::UNKNOWN;
|
|
return currentToken_;
|
|
}
|
|
currentToken_ = Token::END_OF_FILE;
|
|
return currentToken_;
|
|
}
|
|
|
|
Token Lexer::ReadIdentifier(char c)
|
|
{
|
|
StringBuilder sb;
|
|
|
|
sb.Append(c);
|
|
while (!currentFile_->IsEof()) {
|
|
c = currentFile_->PeekChar();
|
|
if (IsAlphabet(c) || c == '_' || IsDecimalDigital(c) || c == '.') {
|
|
c = currentFile_->GetChar();
|
|
sb.Append(c);
|
|
continue;
|
|
}
|
|
if (IsSpace(c)) {
|
|
currentFile_->GetChar();
|
|
}
|
|
break;
|
|
}
|
|
String key = sb.ToString();
|
|
auto it = keywords_.find(key);
|
|
if (it == keywords_.end()) {
|
|
identifier_ = key;
|
|
currentToken_ = Token::IDENTIFIER;
|
|
} else {
|
|
currentToken_ = it->second;
|
|
}
|
|
|
|
return currentToken_;
|
|
}
|
|
|
|
Token Lexer::ReadDecimalDigital(char c)
|
|
{
|
|
StringBuilder sb;
|
|
sb.Append(c);
|
|
while (!currentFile_->IsEof()) {
|
|
c = currentFile_->PeekChar();
|
|
if (IsDecimalDigital(c)) {
|
|
c = currentFile_->GetChar();
|
|
sb.Append(c);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
digit_ = sb.ToString();
|
|
currentToken_ = Token::DIGIT;
|
|
return currentToken_;
|
|
}
|
|
|
|
Token Lexer::ReadLineComment(char c)
|
|
{
|
|
StringBuilder sb;
|
|
|
|
sb.Append(c);
|
|
while (!currentFile_->IsEof()) {
|
|
c = currentFile_->GetChar();
|
|
if (c == '\n') {
|
|
break;
|
|
}
|
|
sb.Append(c);
|
|
}
|
|
comment_ = sb.ToString();
|
|
currentToken_ = Token::COMMENT_LINE;
|
|
return currentToken_;
|
|
}
|
|
|
|
Token Lexer::ReadBlockComment(char c)
|
|
{
|
|
StringBuilder sb;
|
|
|
|
sb.Append(c);
|
|
while (!currentFile_->IsEof()) {
|
|
c = currentFile_->GetChar();
|
|
sb.Append(c);
|
|
if (c == '*' && currentFile_->PeekChar() == '/') {
|
|
c = currentFile_->GetChar();
|
|
sb.Append(c);
|
|
break;
|
|
}
|
|
}
|
|
comment_ = sb.ToString();
|
|
currentToken_ = Token::COMMENT_BLOCK;
|
|
return currentToken_;
|
|
}
|
|
|
|
void Lexer::SkipCurrentLine()
|
|
{
|
|
while (!currentFile_->IsEof()) {
|
|
char c = currentFile_->GetChar();
|
|
if (c == '\n') {
|
|
currentFile_->GetChar();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Lexer::SkipCurrentLine(char untilChar)
|
|
{
|
|
while (!currentFile_->IsEof()) {
|
|
int c = currentFile_->GetChar();
|
|
if (c == untilChar) {
|
|
return true;
|
|
}
|
|
if (c == '\n') {
|
|
currentFile_->GetChar();
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Lexer::Skip(char untilChar)
|
|
{
|
|
while (!currentFile_->IsEof()) {
|
|
int c = currentFile_->GetChar();
|
|
if (c == untilChar) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Lexer::SkipEof()
|
|
{
|
|
while (!currentFile_->IsEof()) {}
|
|
}
|
|
|
|
int Lexer::TokenToChar(Token token)
|
|
{
|
|
switch (token) {
|
|
case Token::ANGLE_BRACKETS_LEFT:
|
|
return '<';
|
|
case Token::ANGLE_BRACKETS_RIGHT:
|
|
return '>';
|
|
case Token::BRACES_LEFT:
|
|
return '{';
|
|
case Token::BRACES_RIGHT:
|
|
return '}';
|
|
case Token::BRACKETS_LEFT:
|
|
return '[';
|
|
case Token::BRACKETS_RIGHT:
|
|
return ']';
|
|
case Token::COMMA:
|
|
return ',';
|
|
case Token::DOT:
|
|
return '.';
|
|
case Token::PARENTHESES_LEFT:
|
|
return '(';
|
|
case Token::PARENTHESES_RIGHT:
|
|
return ')';
|
|
case Token::COLON:
|
|
return ':';
|
|
case Token::SEMICOLON:
|
|
return ';';
|
|
case Token::BOOLEAN:
|
|
case Token::BYTE:
|
|
case Token::CHAR:
|
|
case Token::COMMENT_BLOCK:
|
|
case Token::COMMENT_LINE:
|
|
case Token::DOUBLE:
|
|
case Token::END_OF_FILE:
|
|
case Token::FLOAT:
|
|
case Token::IDENTIFIER:
|
|
case Token::IN:
|
|
case Token::INTEGER:
|
|
case Token::LIST:
|
|
case Token::LONG:
|
|
case Token::MAP:
|
|
case Token::ONEWAY:
|
|
case Token::OUT:
|
|
case Token::SEQUENCEABLE:
|
|
case Token::SHORT:
|
|
case Token::STRING:
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
String Lexer::DumpToken() const
|
|
{
|
|
auto iter = tokenDumps_.find(currentToken_);
|
|
if (iter != tokenDumps_.end()) {
|
|
return iter->second;
|
|
}
|
|
|
|
if (currentToken_ == Token::COMMENT_BLOCK || currentToken_ == Token::COMMENT_LINE) {
|
|
return comment_;
|
|
}
|
|
|
|
if (currentToken_ == Token::IDENTIFIER) {
|
|
return identifier_;
|
|
}
|
|
|
|
return "unknown token";
|
|
}
|
|
} // namespace HDI
|
|
} // namespace OHOS
|