Kinomo JVM
Language
Đồ án trình biên dịch
Trần Phú Quy – Trần Chí Vĩ – Nguyễn Lại Tam Vũ
Kinomo JVM Language
Có bao nhiều ngôn ngữ lập trình hiện nay?
Kinomo JVM Language
Leo núi NNLT = Tạo một NNLT
Kinomo JVM Language
Lexing - Scanning
Là bước đầu tiên khi tạo mới một NNLT, phần tích văn bản theo hướng tuyến tính để
trích xuất được các từ hay còn gọi là token
Kinomo JVM Language
Parsing – Phân tích cú pháp
Bước tiếp theo là parsing. Một ngôn ngữ được xây dựng từ các từ - token đơn giản
thành những thứ phức tạp hơn (biểu thức, câu lệnh) theo cấu trúc ngữ pháp –
grammar cho trước.
Một trình phần tích cú pháp – parser sẽ phân tích các token và dựa theo grammar
đã có để xây dựng cây cú pháp - abstract syntax tree (AST)
Kinomo JVM Language
Parsing – Phân tích cú pháp
Parsing có một lịch sử lâu dài và phong phú trong ngành khoa học máy tính gắn liền
với trí tuệ nhân tạo. Các kỹ thuật phân tích NNLT ngày nay dùng để phân tích ngôn
ngữ tự nhiên của con người bởi các nhà nghiên cứu AI.
Parsing cũng bao gồm cho chúng ta biết về lỗi cú pháp – Syntax error
Kinomo JVM Language
Static analysis
Đối với biểu thức đơn giản như a + b, chúng ta đều hiểu đó chính là a cộng cho b.
Nhưng chúng ta không biết nó đại diện cho đối tượng nào, hay nói dễ hiểu hơn là
chúng là biến toàn cục hay biến cục bộ và chúng được định nghĩa ở đâu?
Hai thuộc tính trong phân tích là ràng buộc & phân giải. Đối với mỗi định danh I
dentifier chúng ta phải tìm ra nơi nó được định nghĩa và nối chúng lại với nhau. Việc
này giúp chúng ta có thể biết được kiểu của chúng và ném lỗi nếu sai kiểu – type
error.
Kinomo JVM Language
Code generation – Tạo mã
Đây là giai đoạn cuối cùng mà khi các bước phía trên được thực hiện xong. Tạo mã
là quá trình chúng ta tạo ra các tệp nhị phân để CPU hoặc Virtual machine có thể
hiểu được.
Các tệp nhị phân có thể là các binary file hoặc là byte code. Trước thập niên 60,
một NNLT chỉ gắn với 1 compiler cố định và nền tảng cố định (ARM, x86 …). Kể từ
năm 60 với sự bùng nổ của máy tính thì vấn đề di động mới được quan tâm. Và byte
code ra đời.
Byte code là đoạn mã trung gian khi biên dịch source code <-> machine code. Mục
đích của byte code đơn giản là giúp NNLT chúng ta có thể chạy mà không quan tâm
đến kiến trúc máy tính với sự giúp sức nữa từ máy ảo – virtual machine
Tiêu biểu có thể kể đến như Java – JVM, Csharp – CLR, Python – PVM.
Kinomo JVM Language
Scanning
Kinomo JVM Language
Scanning - Main
Kinomo là ngôn ngữ có một cú pháp đặc trưng khác với Java, hay C#, nó giống
với JS hay Ruby hơn nên chúng ta có thể tích hơp cả biên dịch và thông dịch cùng
lúc trong Compiler của Kinomo
p u b lic static void m ain(S trin g [] arg s) th row s IO Excep tion {
if (arg s.len g th > 1) {
System .exit(64); // [64]
} else if (arg s.leng th = = 1) {
runFile(args[0]); // Lấấ
y địa chiỉ
fi
le code
} else {
runProm pt(); //REPL
}
} //H àm khở
ở iđộng Com piler
Kinomo JVM Language
Scanning - REPL
Chúng ta sử dụng REPL (Read Eval Print Loop) cho chức năng thông dịch.
private static void runPrompt() throws IOException {
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(input);
for (;;) { // [repl]
System.out.print("> ");
run(reader.readLine());
hadError = false;
}
}
Kinomo JVM Language
Scanning – Error Handing
Cơ chế bắt lỗi, sử dụng biến static trong class chính, quá trình biến dịch sẽ dừng nếu
hadError = true
static boolean hadError = false;
.............
static void error(int line, String message) {
report(line, "", message);
}
private static void report(int line, String where, String mes
sage) {
System.err.println(
"[line " + line + "] Error" + where + ": " + message);
hadError = true;
}
Kinomo JVM Language
Scanning – Token Type
Danh sách các kiểở
u cu
ởa token
enum TokenType {
// Single-character tokens.
LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE,
COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR,
// One or two character tokens.
BANG, BANG_EQUAL,
EQUAL, EQUAL_EQUAL,
GREATER, GREATER_EQUAL,
LESS, LESS_EQUAL,
// Literals.
IDENTIFIER, STRING, NUMBER,
// Keywords.
AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR,
PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE,
EOF
}
Kinomo JVM Language
Scanning – Scan Token
Hàm chính Scanner.java, token 1 kí tự
private void scanToken() {
char c = advance();
switch (c) {
//> one-char-tokens
case '(': addToken(LEFT_PAREN); break;
case ')': addToken(RIGHT_PAREN); break;
case '{': addToken(LEFT_BRACE); break;
case '}': addToken(RIGHT_BRACE); break;
case ',': addToken(COMMA); break;
case '.': addToken(DOT); break;
case '-': addToken(MINUS); break;
case '+': addToken(PLUS); break;
case ';': addToken(SEMICOLON); break;
case '*': addToken(STAR); break;
Kinomo JVM Language
Scanning – Scan Token
Hàm chính Scanner.java, token 2 kí tự
private void scanToken() {
char c = advance();
switch (c) {
//> two-char-tokens
case '!': addToken(match('=') ? BANG_EQUAL : BANG); break;
case '=': addToken(match('=') ? EQUAL_EQUAL : EQUAL); break
;
case '<': addToken(match('=') ? LESS_EQUAL : LESS); break;
case '>': addToken(match('=') ? GREATER_EQUAL : GREATER); b
reak;
---------------------------------------------------private boolean match(char expected) {
if (isAtEnd()) return false;
if (source.charAt(current) != expected) return false;
current++;
return true;
}
Kinomo JVM Language
Scanning – Scan Token
Hàm chính Scanner.java, comments && div operator (flash)
//> slash
case '/':
if (match('/')) {
// Bo
ở qua cho đểế
n cuốế
i dòng (gặp kí tự \n)
while (peek() != '\n' && !isAtEnd()) advance();
} else {
addToken(SLASH);
}
break;
Kinomo JVM Language
Scanning – Scan Token
Hàm chính Scanner.java, whitespaces
//> whitespace
case ' ':
case '\r':
case '\t':
// Ignore
break;
case '\n':
line++;
break;
Kinomo JVM Language
Scanning – Scan Token
Hàm chính Scanner.java, strings
//> string
case '"': string(); break;
------------------------------------------------private void string() {
while (peek() != '"' && !isAtEnd()) {
if (peek() == '\n') line++;
advance();
}
// Unterminated string.
if (isAtEnd()) {
Lox.error(line, "Unterminated string.");
return;
}
…> next slide
Kinomo JVM Language
Scanning – Scan Token
Hàm chính Scanner.java, strings
// The closing ".
advance();
// Substring to get Value
String value = source.substring(start + 1, current - 1);
addToken(STRING, value);
}
Kinomo JVM Language
Scanning – Scan Token
Hàm chính Scanner.java, others (Numbers + alphabet)
default:
//> digit-start
if (isDigit(c)) {
number();
//> identifier-start
} else if (isAlpha(c)) {
identifier();
//< identifier-start
} else {
Lox.error(line, "Unexpected character.");
}
//< digit-start
break;
Kinomo JVM Language
Scanning – Scan Token
Hàm phụ Scanner.java, others (Numbers + alphabet)
private boolean isDigit(char c) {
return c >= '0' && c <= '9'; }
private boolean isAlpha(char c) {
return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
c == '_';}
Kinomo JVM Language
Scanning – Scan Token
Hàm phụ Scanner.java, Numbers. Kiểể
u number dùng float vd(10, 10
.0, 0.123)
private void number() {
while (isDigit(peek())) advance();
// Tìm ‘.’
if (peek() == '.' && isDigit(peekNext())) {
advance();
while (isDigit(peek())) advance();
}
addToken(NUMBER,
Double.parseDouble(source.substring(start, current)));
}
Kinomo JVM Language
Scanning – Scan Token
Hàm phụ Scanner.java, Indentifier (slide 20)
private void identifier() {
while (isAlphaNumeric(peek())) advance();
String text = source.substring(start, curre
nt);
TokenType type = keywords.get(text);
if (type == null) type = IDENTIFIER;
addToken(type);
}
//-> Phân biệt keywords với các indentifi
ers khác. Vd OR vs. ORANGE, AND vs. ANDRO
ID
private static final Map
TokenType> keywords;
static {
keywords = new HashMap<>();
keywords.put("and",
AND);
keywords.put("class", CLASS);
keywords.put("else",
ELSE);
keywords.put("false", FALSE);
keywords.put("for",
FOR);
keywords.put("fun",
FUN);
keywords.put("if",
IF);
keywords.put("nil",
NIL);
keywords.put("or",
OR);
keywords.put("print", PRINT);
keywords.put("return",
RETURN);
keywords.put("super", SUPER);
keywords.put("this",
THIS);
keywords.put("true",
TRUE);
keywords.put("var",
VAR);
keywords.put("while", WHILE);
}
Kinomo JVM Language
Expression
Kinomo JVM Language
Expression
Chúng ta bắt đầu với biểu thức F = 1 + 2 * 3 – 4
Đối với con người thì việc tính biểu thức trung tố như thế này thì cực kỳ đơn giản như
ng đối với máy thì không như vậy. Thứ tự thực hiện sẽ tuần tự như sau…