📄 compiler.cpp
字号:
// work well for user type-in)
//
bool Compiler::compile_file(FILE *file, bool interactive)
{
interactive_mode = interactive;
inf = file; // so that get_token() will read from file
if (!semantics.reset()) return false;
error_flag = false;
token = tokens;
unget_count = 0;
token->typ = TOKEN_OTHER;
istack_top = 0;
indentation[0] = 0;
dedent_count = 0;
newline_flag = false;
line_number = 1;
while (!machine->exit_flag && parse_decl()) ;
return !error_flag;
}
bool Compiler::compile(char *filename)
{
FILE *f = fopen(filename, "r");
bool result;
if (f) {
result = compile_file(f, false);
fclose(f);
} else {
char msg[128];
strcpy(msg, "Compiler: can't open ");
strcat(msg, filename);
report_error(msg);
result = false;
}
return result;
}
bool Compiler::parse_decl()
{
if (get_token()) {
return parse_decl_2();
}
return false;
}
bool Compiler::parse_decl_2()
{
if (token->typ == TOKEN_ID) {
if (streql(token->str, "def")) {
return parse_method();
} else if (streql(token->str, "var")) {
return parse_var();
} else if (streql(token->str, "class")) {
return parse_class();
} else {
// assume we have an immediate statement
// create a method for it
semantics.method_start();
semantics.method_name_is("<immediate command>");
semantics.begin_formals();
semantics.end_of_formals();
if (parse_stmt_2() && semantics.method_end()) {
// execute the method now
Symbol_ptr s_imcd = Symbol::create("<immediate command>", machine);
machine->global_function(s_imcd);
if (machine->error_flag) return false;
machine->call();
return !machine->error_flag;
}
return false; // allow immediate stmt in place of decl
}
} else if (token->typ == TOKEN_NEWLINE) {
return true;
}
return false;
}
bool Compiler::parse_id(char *msg)
{
if (get_token() && token->typ == TOKEN_ID) return true;
expected_id(msg);
return false;
}
bool Compiler::parse_method()
{
if (get_token()) {
if (token->typ == TOKEN_ID &&
semantics.method_start() &&
semantics.method_name_is(token->str)) {
if (parse_formals() &&
parse_colon() &&
parse_stmt_list() &&
semantics.method_end()) {
return true;
}
}
}
return false;
}
bool Compiler::parse_formals()
{
semantics.begin_formals();
if (!get_token() || !streql(token->str, "(")) {
expected_open_paren();
return false;
}
if (!parse_token()) return false;
bool more = true;
bool first = true; // allow ')' only on first time through loop
while (more) {
if (token->typ == TOKEN_ID) {
bool ok = true;
if ((streql(token->str, "optional") &&
(ok = semantics.set_formal_type(FORMAL_OPTIONAL))) ||
(streql(token->str, "keyword") &&
(ok = semantics.set_formal_type(FORMAL_KEYWORD))) ||
(streql(token->str, "rest") &&
(ok = semantics.set_formal_type(FORMAL_REST))) ||
(streql(token->str, "dictionary") &&
(ok = semantics.set_formal_type(FORMAL_DICTIONARY))) ||
(streql(token->str, "required") &&
(ok = semantics.set_formal_type(FORMAL_REQUIRED)))) {
if (!parse_id("formal parameter")) return false;
}
// if a set_formal_type failed, return now:
if (!ok) return false;
if (!semantics.formal_is(token->str)) return false;
// look for default value specification:
if (get_token()) {
if (streql(token->str, "=")) {
if (!parse_default_value()) return false;
} else unget_token();
} else unget_token();
// look for comma
if (get_token()) {
more = streql(token->str, ",");
if (more) {
if (!parse_token()) return false;
}
} else { // no token!
expected_close_paren();
return false;
}
} else if (first && streql(token->str, ")")) {
more = false;
} else break;
first = false;
}
if (streql(token->str, ")")) {
return semantics.end_of_formals();
} else {
expected_close_paren_or_formal();
return false();
}
}
int Compiler::hex_to_int(char h)
{
if (isdigit(h)) return h - '0';
else if (isxdigit(h)) return tolower(h) - 'a' + 10;
expected_hex_constant();
return 0;
}
int Compiler::oct_to_int(char o)
{
if ((o >= '0') && (o <= '7')) return o - '0';
expected_oct_constant();
return 0;
}
int Compiler::dec_to_int(char d)
{
if (isdigit(d)) return d - '0';
expected_number_constant();
return 0;
}
int64 Compiler::string_to_int(char *s)
{
int64 result = 0;
int sign = 1;
if (!s || *s == 0) return result;
if (*s == '-') {
if (*s++ == 0) return result;
sign = -1;
}
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { // hexadecimal
for (int i = 2; s[i] && !error_flag; i++) {
result = (result << 4) + hex_to_int(s[i]);
}
result *= sign;
} else if (s[0] == '0') { // octal
for (int i = 1; s[i] && !error_flag; i++) {
result = (result << 3) + oct_to_int(s[i]);
}
result *= sign;
} else {
// since negative numbers can be larger (in magnitude) than positive
// we'll compute decimal numbers in the negative form and then apply
// the sign.
for (int i = 0; s[i] && !error_flag; i++) {
result = (result * 10) - dec_to_int(s[i]);
}
result *= -sign;
}
return result;
}
bool Compiler::parse_default_value()
{
if (!parse_token()) return false;
// assume value is in one token
if (token->typ == TOKEN_LONG) {
int64 val = string_to_int(token->str);
if (error_flag) return false;
return semantics.default_value(
FLong::create(val, machine));
} else if (token->typ == TOKEN_DOUBLE) {
// make sure there is a + or - after e:
char *pos = strpbrk(token->str, "eE");
if (pos && pos[1] != '+' && pos[1] != '-') {
// open up some space:
memmove(pos + 2, pos + 1, strlen(pos + 1));
pos[1] = '+';
}
return semantics.default_value(
FDouble::create(atof(token->str), machine));
} else if (token->typ == TOKEN_STRING) {
return semantics.default_value(
FString::create(token->str + 1, machine));
} else if (token->typ == TOKEN_SYMBOL) {
return semantics.default_value(
Symbol::create(token->str + 1, machine));
} else return false;
}
bool Compiler::parse_stmt()
{
if (get_token()) {
return parse_stmt_2();
}
expected_statement();
return false;
}
// parse_stmt_2 -- parse stmt, assumes first token already gotten
//
bool Compiler::parse_stmt_2()
{
if (streql(token->str, "class") || streql(token->str, "var") ||
streql(token->str, "def")) {
return parse_decl_2();
} else if (streql(token->str, "if")) {
return parse_if();
} else if (streql(token->str, "while")) {
return parse_while();
} else if (streql(token->str, "for")) {
return parse_for();
} else if (streql(token->str, "return")) {
return parse_return();
} else if (streql(token->str, "print")) {
return parse_print();
} else if (streql(token->str, "load")) {
return parse_load();
} else if (token->typ == TOKEN_ID) {
char id[STRING_MAX];
strcpy(id, token->str);
if (!parse_id_expr(id)) return false;
if (get_token()) {
if (streql(token->str, "=")) {
return parse_assign();
} else if (token->typ == TOKEN_NEWLINE) {
semantics.end_id_expr();
return true;
}
}
expected_newline();
} else {
expected_statement();
}
return false;
}
bool Compiler::parse_if()
{
// at this point, IF has already been parsed
if (parse_expr()) {
semantics.if_true();
if (parse_colon() && parse_stmt_list()) {
long elif_count = 0;
while (get_token() && streql(token->str, "elif")) {
semantics.if_else();
if (parse_expr()) {
semantics.if_true();
if (parse_colon() && parse_stmt_list()) {
elif_count++;
trace("elif_count %d\n", elif_count);
} else return false;
} else return false;
}
if (streql(token->str, "else")) {
semantics.if_else();
if (parse_colon() && parse_stmt_list()) {
// if_end called for each elif and for else
while (elif_count >= 0) {
semantics.if_end();
elif_count--;
}
return true;
} else return false;
} else {
unget_token();
while (elif_count >= 0) {
semantics.if_end();
elif_count--;
}
return true;
}
}
}
return false;
}
bool Compiler::parse_while()
{
return semantics.while_begin() &&
parse_expr() && parse_colon() &&
semantics.while_true() &&
parse_stmt_list() &&
semantics.while_end();
}
bool Compiler::parse_for()
{
if (!parse_token()) return false;
if (token->typ != TOKEN_ID) {
expected_id(token->str);
return false;
}
if (!semantics.for_var(token->str)) return false;
if (!parse_token()) return false;
else if (streql(token->str, "=")) {
if (!parse_expr() || !semantics.for_init())
return false;
if (!get_token() || !streql(token->str, "to")) {
expected_to();
return false;
}
if (!(parse_expr() && semantics.for_to()))
return false;
if (!parse_token()) return false;
if (streql(token->str, "by")) {
if (!parse_expr() || !semantics.for_by(true))
return false;
} else {
unget_token();
if (!semantics.for_by(false)) return false;
}
if (!parse_colon() || !parse_stmt_list() ||
!semantics.for_end_range())
return false;
} else if (streql(token->str, "in")) {
if (!parse_expr() || !semantics.for_array() ||
!parse_colon() || !parse_stmt_list() ||
!semantics.for_end_elements())
return false;
} else {
expected_equal_or_in();
return false;
}
return true;
}
bool Compiler::parse_indent()
{
if (get_token() && token->typ == TOKEN_INDENT) {
return true;
}
expected_indent();
return false;
}
bool Compiler::parse_newline()
{
if (get_token() && token->typ == TOKEN_NEWLINE) {
return true;
}
expected_newline();
return false;
}
bool Compiler::parse_return()
{
if (get_token() && token->typ == TOKEN_NEWLINE) {
return semantics.return_null();
}
unget_token();
return parse_expr() && parse_newline() && semantics.return_end();
}
bool Compiler::parse_load()
{
return parse_expr() && parse_newline() && semantics.load_end();
}
bool Compiler::parse_print()
{
bool print_endl = true;
while (true) {
// look for an expression
if (!parse_token()) return false;
if (token->typ == TOKEN_NEWLINE) {
if (print_endl) return semantics.print_end();
else return true;
} else if (unget_token() && parse_expr()) {
semantics.print_expr();
} else return false; // no expression found
print_endl = false;
// look for a separator
if (!parse_token()) return false;
if (token->typ == TOKEN_NEWLINE) {
return semantics.print_end();
} else if (streql(token->str, ",")) {
semantics.print_comma();
} else if (streql(token->str, ";")) {
// nothing
} else expected_comma();
}
}
bool Compiler::parse_stmt_list()
{
if (!parse_token()) return false;
if (token->typ != TOKEN_NEWLINE) {
return parse_stmt_2(); // just one statement after a colon
}
if (!parse_indent()) return false;
while (true) {
if (get_token()) {
if (token->typ == TOKEN_DEDENT) {
return true;
} else if (parse_stmt_2()) {
// continue parsing stmts
} else break;
} else {
expected_statement();
break;
}
}
return false;
}
bool Compiler::parse_assign()
{
// expr and "=" have already been parsed
return semantics.rval2lval() &&
parse_expr() &&
parse_newline() &&
semantics.assign_end();
}
/*
bool Compiler::parse_assign_id(char *id)
{
return parse_expr() && parse_newline() && semantics.assign_id(id);
}
*/
bool Compiler::parse_expr()
{
if (parse_conj()) {
return parse_disjunctions();
}
return false;
}
bool Compiler::parse_conj()
{
if (parse_relation()) {
return parse_conjunctions();
}
return false;
}
bool Compiler::parse_relation()
{
if (parse_sum()) {
if (parse_relop()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -