花了5篇才把一個字符串詞法給解析完,不知道要多久才能刷完整個流程,GC、複雜數據類型的V8實現那些估計又是幾十篇,天吶,真是給本身挖了個大坑。
前面幾篇實際上只是執行了scanner.Initialize方法,並未開始全面解析,繼續跑流程。
FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
scanner_.Initialize();
if (FLAG_harmony_hashbang) {
scanner_.SkipHashBang();
}
FunctionLiteral* result = DoParseProgram(isolate, info);
return result;
}複製代碼
後面的方法域都在Parser類下,畢竟這是整個AST的執行類,parseInfo只是一個編譯信息的存儲類,直接進DoParseProgram方法。
FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
FunctionLiteral* result = nullptr;
{
ScopedPtrList<Statement> body(pointer_buffer());
int beg_pos = scanner()->location().beg_pos;
if (parsing_module_) {
} else if (info->is_wrapped_as_function()) {
ParseWrapped(isolate, info, &body, scope, zone());
} else {
this->scope()->SetLanguageMode(info->language_mode());
ParseStatementList(&body, Token::EOS);
}
}
return result;
}複製代碼
這裏對編譯描述類進行查詢,判斷待編譯字符串是不是模塊、包裝函數,會進入不一樣的分支,因爲測試代碼只是兩個字符串相加,因此進入最後的分支。
void ParserBase<Impl>::ParseStatementList(StatementListT* body, Token::Value end_token) {
while (peek() == Token::STRING) {
bool use_strict = false;
bool use_asm = false;
Scanner::Location token_loc = scanner()->peek_location();
if (scanner()->NextLiteralExactlyEquals("use strict")) {
use_strict = true;
} else if (scanner()->NextLiteralExactlyEquals("use asm")) {
use_asm = true;
}
StatementT stat = ParseStatementListItem();
if (use_strict) {
} else if (use_asm) {
} else {
RaiseLanguageMode(LanguageMode::kSloppy);
}
}
TargetScopeT target_scope(this);
while (peek() != end_token) {
StatementT stat = ParseStatementListItem();
if (impl()->IsNull(stat)) return;
if (stat->IsEmptyStatement()) continue;
body->Add(stat);
}
}複製代碼
這一步v8對以前解析的第一個詞法進行了判斷,來選擇是否開啓嚴格模式或者asm模式,能夠看一眼嚴格模式定義。
To invoke strict mode for an entire script, put the exact statement "use strict"; (or 'use strict';) before any other statements.
因爲這個語句必須出如今最前面,因此會在進行全面轉換前判斷待編譯字符串的第一個Token是否是嚴格等於這個字符串,來設置編譯模式。
這裏還有另一個新鮮的配置,即"use asm",大部分人不會接觸到這個東西,asm是JavaScript的一個子集,雖然語法總的來講也是JS的,可是很是難閱讀,對於機器來講更加友好。若是用了這個配置,v8會跳過一些階段,直接將代碼編譯成機器指令(
貼一個介紹連接)。
若是不配置模式,v8會以普通模式來編譯代碼,隨後底部的while循環指向了全面的AST轉換。
先簡單介紹一下AST的容器body,初始化代碼以下。
ScopedPtrList<Statement> body(pointer_buffer());複製代碼
這裏的類型包含兩部分,一個是容器類ScopePtrList,一個是內容Statement,先看容器。
template <typename T>
class ScopedPtrList final {
public:
void Add(T* value) {
buffer_.push_back(value);
++end_;
}
private:
std::vector<void*>& buffer_;
size_t start_;
size_t end_;
}複製代碼
象徵性的給一些屬性和方法,傳統的vector一把梭,知道一個Add方法就差很少了,反正都那樣。
至於Statement類則是標準的抽象語法樹節點類,簡單看一下定義就好了,其自己沒有什麼東西,大量的枚舉類型都定義在父類上,暫時不展開。
class Statement : public AstNode {
protected:
Statement(int position, NodeType type) : AstNode(position, type) {}
static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex;
};複製代碼
轉換的AST會以Statement類存儲,並經過Add方法加到容器中。
這一篇感受啥都沒寫,先這樣吧,下一篇開始正式全面解析AST。