/* * parse.c */ #include #include #include #include "emalloc.h" #include "parse.h" #include "scan.h" #include "token.h" static void error(const char *msg, enum token token, const union token_attribute *token_attr) { fprintf(stderr, "Syntax error on line %u: %s; current token is ", scan_linenr, msg); token_print(stderr, token, token_attr); fprintf(stderr, "\n"); } static enum token save_token = T_EOF; static union token_attribute save_token_attr; static enum token token_get(union token_attribute *token_attr) { enum token token; token = save_token; if (token != T_EOF) { *token_attr = save_token_attr; save_token = T_EOF; return token; } return scan(token_attr); } static void token_unget(enum token token, const union token_attribute *token_attr) { save_token = token; save_token_attr = *token_attr; } /* * Expression grammar: * The productions are listed from highest to lowest precedence. * All infix operators are left-associative. * * E -> '(' E ')' | | | -E | ~E * | E MOP E * | E BOP E * | E AOP E * | E && E * | E || E * * MOP -> * | / | % | << | >> * BOP -> '|' | & | ^ | ! * AOP -> + | - | == | <> | != | < | > | >= | <= */ static struct expr *make_expr(enum expr_tag tag) { struct expr *expr; expr = emalloc(sizeof *expr); expr->tag = tag; return expr; } static void free_expr(struct expr *expr) { if (expr) { switch (expr->tag) { case E_UNARY: free_expr(expr->u.e_unary.expr); break; case E_BINARY: free_expr(expr->u.e_binary.expr1); free_expr(expr->u.e_binary.expr2); break; default: break; } free(expr); } } static struct expr *make_uinteger_expr(pdp10_uint36_t val) { struct expr *expr; expr = make_expr(E_UINTEGER); expr->u.e_uinteger.val = val; return expr; } static struct expr *make_symbol_expr(const struct strnode *name) { struct expr *expr; expr = make_expr(E_SYMBOL); expr->u.e_symbol.name = name; return expr; } static struct expr *make_unary_expr(enum expr_unop unop, struct expr *expr1) { struct expr *expr; expr = make_expr(E_UNARY); expr->u.e_unary.unop = unop; expr->u.e_unary.expr = expr1; return expr; } static struct expr *make_binary_expr(struct expr *expr1, enum expr_binop binop, struct expr *expr2) { struct expr *expr; expr = make_expr(E_BINARY); expr->u.e_binary.expr1 = expr1; expr->u.e_binary.binop = binop; expr->u.e_binary.expr2 = expr2; return expr; } static struct expr *parse_expr(void); /* forward */ static struct expr *parse_atomic_expr(void) { enum token token; union token_attribute token_attr; struct expr *expr; token = token_get(&token_attr); switch (token) { case T_UINTEGER: return make_uinteger_expr(token_attr.uint); case T_SYMBOL: return make_symbol_expr(strtab_enter(token_attr.text)); case T_LPAREN: expr = parse_expr(); token = token_get(&token_attr); if (token != T_RPAREN) { error("junk after expression, expected right parenthesis", token, &token_attr); return NULL; } return expr; case T_MINUS: return make_unary_expr(E_UMINUS, parse_atomic_expr()); case T_TILDE: return make_unary_expr(E_NOT, parse_atomic_expr()); default: error("bad expression, expected integer, symbol, unary operator, or left parenthesis", token, &token_attr); return NULL; } } static struct expr *parse_multiplicative_expr(void) { struct expr *expr1; struct expr *expr2; enum token token; union token_attribute token_attr; enum expr_binop binop; expr1 = parse_atomic_expr(); if (!expr1) return NULL; for (;;) { token = token_get(&token_attr); switch (token) { case T_MUL: binop = E_MUL; break; case T_DIV: binop = E_DIV; break; case T_REM: binop = E_REM; break; case T_LSHIFT: binop = E_LSHIFT; break; case T_RSHIFT: binop = E_RSHIFT; break; default: token_unget(token, &token_attr); return expr1; } expr2 = parse_atomic_expr(); if (!expr2) return NULL; expr1 = make_binary_expr(expr1, binop, expr2); } } static struct expr *parse_bitwise_expr(void) { struct expr *expr1; struct expr *expr2; enum token token; union token_attribute token_attr; enum expr_binop binop; expr1 = parse_multiplicative_expr(); if (!expr1) return NULL; for (;;) { token = token_get(&token_attr); switch (token) { case T_OR: binop = E_OR; break; case T_AND: binop = E_AND; break; case T_CARET: binop = E_XOR; break; case T_BANG: binop = E_ORNOT; break; default: token_unget(token, &token_attr); return expr1; } expr2 = parse_multiplicative_expr(); if (!expr2) return NULL; expr1 = make_binary_expr(expr1, binop, expr2); } } static struct expr *parse_additive_expr(void) { struct expr *expr1; struct expr *expr2; enum token token; union token_attribute token_attr; enum expr_binop binop; expr1 = parse_bitwise_expr(); if (!expr1) return NULL; for (;;) { token = token_get(&token_attr); switch (token) { case T_PLUS: binop = E_ADD; break; case T_MINUS: binop = E_SUB; break; case T_EQEQ: binop = E_EQ; break; case T_NEQ: binop = E_NE; break; case T_LT: binop = E_LT; break; case T_GT: binop = E_GT; break; case T_GE: binop = E_GE; break; case T_LE: binop = E_LE; break; default: token_unget(token, &token_attr); return expr1; } expr2 = parse_bitwise_expr(); if (!expr2) return NULL; expr1 = make_binary_expr(expr1, binop, expr2); } } static struct expr *parse_andand_expr(void) { struct expr *expr1; struct expr *expr2; enum token token; union token_attribute token_attr; expr1 = parse_additive_expr(); if (!expr1) return NULL; for (;;) { token = token_get(&token_attr); if (token != T_ANDAND) { token_unget(token, &token_attr); return expr1; } expr2 = parse_additive_expr(); if (!expr2) return NULL; expr1 = make_binary_expr(expr1, E_ANDAND, expr2); } } static struct expr *parse_oror_expr(void) { struct expr *expr1; struct expr *expr2; enum token token; union token_attribute token_attr; expr1 = parse_andand_expr(); if (!expr1) return NULL; for (;;) { token = token_get(&token_attr); if (token != T_OROR) { token_unget(token, &token_attr); return expr1; } expr2 = parse_andand_expr(); if (!expr2) return NULL; expr1 = make_binary_expr(expr1, E_OROR, expr2); } } static struct expr *parse_expr(void) { return parse_oror_expr(); } static int parse_expr_opt(struct expr **exprp) { enum token token; union token_attribute token_attr; token = token_get(&token_attr); token_unget(token, &token_attr); switch (token) { case T_UINTEGER: case T_SYMBOL: case T_LPAREN: case T_MINUS: case T_TILDE: *exprp = parse_expr(); return *exprp == NULL ? -1 : 1; default: return 0; } } static int parse_dot_align(struct stmt *stmt, unsigned int flags) { enum token token; union token_attribute token_attr; struct expr *expr; stmt->tag = S_ALIGN; stmt->u.s_align.flags = flags; expr = parse_expr(); if (!expr) return -1; stmt->u.s_align.balign = expr; token = token_get(&token_attr); if (token == T_COMMA) { expr = parse_expr(); if (!expr) return -1; stmt->u.s_align.fill = expr; token = token_get(&token_attr); if (token == T_COMMA) { expr = parse_expr(); if (!expr) return -1; stmt->u.s_align.maxskip = expr; token = token_get(&token_attr); } } if (token != T_NEWLINE) { error("junk after .{,b,p2}align{,w,l} directive", token, &token_attr); return -1; } return 1; } static struct string_list *make_string_list(const struct strnode *string, struct string_list *next) { struct string_list *list; list = emalloc(sizeof *list); list->string = string; list->next = next; return list; } static int parse_string_list(struct stmt *stmt, enum stmt_tag tag) { enum token token; union token_attribute token_attr; struct string_list **nextp; struct string_list *temp; stmt->tag = tag; stmt->u.s_string_list.list = NULL; nextp = &stmt->u.s_string_list.list; token = token_get(&token_attr); if (token == T_STRING) for (;;) { temp = make_string_list(strtab_enter(token_attr.text), NULL); *nextp = temp; nextp = &temp->next; token = token_get(&token_attr); if (token != T_COMMA) break; token = token_get(&token_attr); if (token != T_STRING) { error("junk after ',' in .asci{i,z} directive", token, &token_attr); return -1; } } if (token != T_NEWLINE) { error("junk after .asci{i,z} directive", token, &token_attr); return -1; } return 1; } static struct expr_list *make_expr_list(struct expr *expr, struct expr_list *next) { struct expr_list *list; list = emalloc(sizeof *list); list->expr = expr; list->next = next; return list; } static int parse_expr_list(struct stmt *stmt, enum stmt_tag tag) { enum token token; union token_attribute token_attr; struct expr_list **nextp; struct expr_list *temp; struct expr *expr; int status; stmt->tag = tag; stmt->u.s_expr_list.list = NULL; nextp = &stmt->u.s_expr_list.list; status = parse_expr_opt(&expr); if (status < 0) return -1; else if (status == 0) token = token_get(&token_attr); else for (;;) { temp = make_expr_list(expr, NULL); *nextp = temp; nextp = &temp->next; token = token_get(&token_attr); if (token != T_COMMA) break; expr = parse_expr(); if (!expr) return -1; } if (token != T_NEWLINE) { error("junk after .{byte,long,short} directive", token, &token_attr); return -1; } return 1; } static int parse_string(struct stmt *stmt, enum stmt_tag tag) { enum token token; union token_attribute token_attr; token = token_get(&token_attr); if (token == T_STRING) { stmt->u.s_string.string = strtab_enter(token_attr.text); stmt->tag = tag; token = token_get(&token_attr); if (token == T_NEWLINE) return 1; } error("junk after .file/.ident directive", token, &token_attr); return -1; } static int parse_dot_popsection(struct stmt *stmt) { enum token token; union token_attribute token_attr; token = token_get(&token_attr); if (token == T_NEWLINE) { stmt->tag = S_POPSECTION; return 1; } error("junk after .popsection directive", token, &token_attr); return -1; } static int parse_dot_previous(struct stmt *stmt) { enum token token; union token_attribute token_attr; token = token_get(&token_attr); if (token == T_NEWLINE) { stmt->tag = S_PREVIOUS; return 1; } error("junk after .previous directive", token, &token_attr); return -1; } static int parse_dot_subsection(struct stmt *stmt) { struct expr *expr; enum token token; union token_attribute token_attr; expr = parse_expr(); if (!expr) return -1; stmt->u.s_subsection.expr = expr; token = token_get(&token_attr); if (token == T_NEWLINE) { stmt->tag = S_SUBSECTION; return 1; } error("junk after .subsection directive", token, &token_attr); return -1; } static int parse_name_list(struct stmt *stmt, enum stmt_tag tag) { enum token token; union token_attribute token_attr; struct string_list **nextp; struct string_list *temp; stmt->tag = tag; stmt->u.s_string_list.list = NULL; nextp = &stmt->u.s_string_list.list; token = token_get(&token_attr); if (token == T_SYMBOL) for (;;) { temp = make_string_list(strtab_enter(token_attr.text), NULL); *nextp = temp; nextp = &temp->next; token = token_get(&token_attr); if (token != T_COMMA) break; token = token_get(&token_attr); if (token != T_SYMBOL) { error("junk after ',' in .globl/.hidden/.internal/.local/.protected directive", token, &token_attr); return -1; } } if (token != T_NEWLINE) { error("junk after .globl/.hidden/.internal/.local/.protected directive", token, &token_attr); return -1; } return 1; } static int parse_dot_comm(struct stmt *stmt) { enum token token; union token_attribute token_attr; struct expr *expr; token = token_get(&token_attr); if (token == T_SYMBOL) { stmt->u.s_comm.name = strtab_enter(token_attr.text); token = token_get(&token_attr); if (token == T_COMMA) { expr = parse_expr(); if (!expr) return -1; stmt->u.s_comm.length = expr; token = token_get(&token_attr); if (token == T_COMMA) { expr = parse_expr(); if (!expr) return -1; stmt->u.s_comm.balign = expr; token = token_get(&token_attr); } else stmt->u.s_comm.balign = NULL; if (token == T_NEWLINE) { stmt->tag = S_COMM; return 1; } } } error("junk after .comm directive", token, &token_attr); return -1; } static int parse_dot_org(struct stmt *stmt) { enum token token; union token_attribute token_attr; struct expr *expr; expr = parse_expr(); if (!expr) return -1; stmt->u.s_org.newlc = expr; token = token_get(&token_attr); if (token == T_COMMA) { expr = parse_expr(); if (!expr) return -1; stmt->u.s_org.fill = expr; token = token_get(&token_attr); } else stmt->u.s_org.fill = NULL; if (token == T_NEWLINE) { stmt->tag = S_ORG; return 1; } error("junk after .org directive", token, &token_attr); return -1; } static int parse_setsize(struct stmt *stmt, enum stmt_tag tag) { enum token token; union token_attribute token_attr; struct expr *expr; token = token_get(&token_attr); if (token == T_SYMBOL) { stmt->u.s_setsize.name = strtab_enter(token_attr.text); token = token_get(&token_attr); if (token == T_COMMA) { expr = parse_expr(); if (!expr) return -1; stmt->u.s_setsize.expr = expr; token = token_get(&token_attr); if (token == T_NEWLINE) { stmt->tag = tag; return 1; } } } error("junk after .set/.size directive", token, &token_attr); return -1; } static int parse_sh_flags(Elf36_Word *sh_flags) { enum token token; union token_attribute token_attr; const char *f; Elf36_Word flag; token = token_get(&token_attr); if (token == T_STRING) { f = token_attr.text; for (; ; *sh_flags |= flag, ++f) { switch (*f) { case 'a': flag = SHF_ALLOC; continue; case 'e': flag = SHF_EXCLUDE; continue; case 'w': flag = SHF_WRITE; continue; case 'M': flag = SHF_MERGE; continue; case 'S': flag = SHF_STRINGS; continue; case 'G': if (*sh_flags & (1 << 19)) break; flag = SHF_GROUP; continue; case 'T': flag = SHF_TLS; continue; case '?': if (*sh_flags & SHF_GROUP) break; flag = 1 << 19; /* XXX: FAKE FAKE FAKE */ continue; case '\0': /* XXX: free the string? */ return 1; default: break; } break; } } error("invalid section flags", token, &token_attr); return -1; } static int parse_sh_type(Elf36_Word *sh_type) { enum token token; union token_attribute token_attr; Elf36_Word type; token = token_get(&token_attr); if (token == T_AT) { token = token_get(&token_attr); if (token == T_SYMBOL) { do { if (strcmp(token_attr.text, "progbits") == 0) type = SHT_PROGBITS; else if (strcmp(token_attr.text, "nobits") == 0) type = SHT_NOBITS; else if (strcmp(token_attr.text, "note") == 0) type = SHT_NOTE; else if (strcmp(token_attr.text, "init_array") == 0) type = SHT_INIT_ARRAY; else if (strcmp(token_attr.text, "fini_array") == 0) type = SHT_FINI_ARRAY; else if (strcmp(token_attr.text, "preinit_array") == 0) type = SHT_PREINIT_ARRAY; else break; *sh_type = type; return 1; } while (0); } } error("invalid section type", token, &token_attr); return -1; } static int parse_dot_section(struct stmt *stmt, int is_pushsection) { enum token token; union token_attribute token_attr; stmt->u.s_section.subsectnr = NULL; stmt->u.s_section.sh_flags = 0; stmt->u.s_section.sh_type = 0; stmt->u.s_section.sh_entsize = NULL; stmt->u.s_section.groupname = NULL; stmt->u.s_section.linkage = NULL; token = token_get(&token_attr); if (token == T_SYMBOL) { stmt->u.s_section.name = strtab_enter(token_attr.text); token = token_get(&token_attr); do { if (is_pushsection) { if (token != T_COMMA) break; stmt->u.s_section.subsectnr = parse_expr(); if (!stmt->u.s_section.subsectnr) return -1; token = token_get(&token_attr); } if (token != T_COMMA) break; if (parse_sh_flags(&stmt->u.s_section.sh_flags) < 1) return -1; token = token_get(&token_attr); if (token != T_COMMA) { if (stmt->u.s_section.sh_flags & (SHF_MERGE | SHF_GROUP)) { error("section flags with M and/or G not followed by ,@type", token, &token_attr); return -1; } break; } if (parse_sh_type(&stmt->u.s_section.sh_type) < 0) return -1; token = token_get(&token_attr); if (stmt->u.s_section.sh_flags & SHF_MERGE) { if (token != T_COMMA) { error("section flags with M not followed by entsize", token, &token_attr); return -1; } stmt->u.s_section.sh_entsize = parse_expr(); if (!stmt->u.s_section.sh_entsize) return -1; token = token_get(&token_attr); } if (stmt->u.s_section.sh_flags & SHF_GROUP) { if (token != T_COMMA) { error("section flags with G not followed by groupname", token, &token_attr); return -1; } token = token_get(&token_attr); if (token != T_SYMBOL) { error("section group with invalid groupname", token, &token_attr); return -1; } stmt->u.s_section.groupname = strtab_enter(token_attr.text); token = token_get(&token_attr); if (token != T_COMMA) break; token = token_get(&token_attr); if (token != T_SYMBOL) { error("section group with invalid linkage", token, &token_attr); return -1; } stmt->u.s_section.linkage = strtab_enter(token_attr.text); token = token_get(&token_attr); } } while (0); if (token == T_NEWLINE) { stmt->tag = is_pushsection ? S_PUSHSECTION : S_SECTION; return 1; } } error("junk after .section/.pushsection directive", token, &token_attr); return -1; } static int parse_oldstyle_section(struct stmt *stmt, const char *name) { enum token token; union token_attribute token_attr; stmt->u.s_section.subsectnr = NULL; stmt->u.s_section.sh_flags = 0; stmt->u.s_section.sh_type = 0; stmt->u.s_section.sh_entsize = NULL; stmt->u.s_section.groupname = NULL; stmt->u.s_section.linkage = NULL; stmt->u.s_section.name = strtab_enter(name); token = token_get(&token_attr); if (token == T_COMMA) { stmt->u.s_section.subsectnr = parse_expr(); if (!stmt->u.s_section.subsectnr) return -1; token = token_get(&token_attr); } if (token == T_NEWLINE) { stmt->tag = S_SECTION; return 1; } error("junk after old-style section directive", token, &token_attr); return -1; } /* * Recognize: * * ":" * "=" "\n" * (( | ) ",")? ("@"? ("(" ( | ) ")")?)? "\n" * "\n" [equivalent to "," "\n"] */ static int make_insn(struct stmt *stmt, union token_attribute *symbol_attr, unsigned int accumulator, int at, struct expr *expr, unsigned int indexreg) { stmt->tag = S_INSN; stmt->u.s_insn.name = strtab_enter(symbol_attr->text); stmt->u.s_insn.accumulator = accumulator; stmt->u.s_insn.at = at; stmt->u.s_insn.expr = expr; stmt->u.s_insn.indexreg = indexreg; return 1; } static int parse_insn_after_lparen(struct stmt *stmt, union token_attribute *symbol_attr, unsigned int accumulator, int at, struct expr *expr) { enum token token; union token_attribute token_attr; token = token_get(&token_attr); if (token == T_UINTEGER || token == T_REGISTER) { unsigned int indexreg; indexreg = token_attr.uint; token = token_get(&token_attr); if (token == T_RPAREN) { token = token_get(&token_attr); if (token == T_NEWLINE) return make_insn(stmt, symbol_attr, accumulator, at, expr, indexreg); } } error("junk in of after index expression", token, &token_attr); return -1; } static int parse_insn_expr(struct stmt *stmt, union token_attribute *symbol_attr, unsigned int accumulator, int at) { struct expr *expr; enum token token; union token_attribute token_attr; expr = parse_expr(); if (!expr) return -1; token = token_get(&token_attr); switch (token) { case T_NEWLINE: return make_insn(stmt, symbol_attr, accumulator, at, expr, 0); case T_LPAREN: return parse_insn_after_lparen(stmt, symbol_attr, accumulator, at, expr); default: error("junk after ", token, &token_attr); return -1; } } static int parse_insn_after_comma(struct stmt *stmt, union token_attribute *symbol_attr, unsigned int accumulator) { enum token token; union token_attribute token_attr; token = token_get(&token_attr); switch (token) { case T_NEWLINE: return make_insn(stmt, symbol_attr, accumulator, 0, NULL, 0); case T_AT: return parse_insn_expr(stmt, symbol_attr, accumulator, 1); case T_UINTEGER: case T_LPAREN: case T_MINUS: case T_TILDE: token_unget(token, &token_attr); return parse_insn_expr(stmt, symbol_attr, accumulator, 0); default: error("junk after ','", token, &token_attr); return -1; } } static int parse_symbol(struct stmt *stmt, union token_attribute *symbol_attr) { enum token token; union token_attribute token_attr; token = token_get(&token_attr); switch (token) { case T_COLON: stmt->u.s_string.string = strtab_enter(symbol_attr->text); stmt->tag = S_LABEL; return 1; case T_EQ: /* =\n --> .set ,\n */ { stmt->u.s_setsize.expr = parse_expr(); if (stmt->u.s_setsize.expr != NULL) { token = token_get(&token_attr); if (token == T_NEWLINE) { stmt->u.s_setsize.name = strtab_enter(symbol_attr->text); stmt->tag = S_SET; return 1; } } error("junk after =", token, &token_attr); return -1; } case T_AT: /* the part needs to be present to avoid ambiguities with the "()" index part */ return parse_insn_expr(stmt, symbol_attr, 0, 1); case T_REGISTER: { union token_attribute token_attr2; token = token_get(&token_attr2); if (token == T_COMMA) return parse_insn_after_comma(stmt, symbol_attr, token_attr.uint); if (token == T_NEWLINE) return make_insn(stmt, symbol_attr, token_attr.uint, 0, NULL, 0); error("junk after ", token, &token_attr2); return -1; } case T_NEWLINE: return make_insn(stmt, symbol_attr, 0, 0, NULL, 0); case T_UINTEGER: { /* * This may be the part of the instruction, * or the start of the part. In the first case it's followed * by ",", and in the second case it's followed by , "(", * or "\n", while the entire is followed by "(" or "\n". * * We could distinguish between these two cases by scanning another token, * but then in the case we'd have to either push back two tokens, * or rewrite parse_expr() so that it could be entered with the left-most * already parsed. Both options are doable, but inefficient * or requiring ugly code. * * Instead we push back the initial and parse . Afterwards * we inspect the parse tree of and the next token, and from that we * can identify which case applied, and complete the parse. */ struct expr *expr; union token_attribute token_attr2; token_unget(token, &token_attr); expr = parse_expr(); if (!expr) return -1; token = token_get(&token_attr2); switch (token) { case T_COMMA: if (expr->tag == E_UINTEGER) { /* "," ... */ free_expr(expr); return parse_insn_after_comma(stmt, symbol_attr, token_attr.uint); } break; /* "," ... is a syntax error */ case T_NEWLINE: /* "\n" */ return make_insn(stmt, symbol_attr, 0, 0, expr, 0); case T_LPAREN: /* "(" ... */ return parse_insn_after_lparen(stmt, symbol_attr, 0, 0, expr); default: break; } error("junk after ", token, &token_attr2); return -1; } /* the following four are FIRST() \ {T_UINTEGER}, see parse_expr_opt() */ case T_SYMBOL: case T_LPAREN: case T_MINUS: case T_TILDE: token_unget(token, &token_attr); return parse_insn_expr(stmt, symbol_attr, 0, 0); default: error("junk after ", token, &token_attr); return -1; } } int parse_stmt(struct stmt *stmt) { enum token token; union token_attribute token_attr; for (;;) { token = token_get(&token_attr); switch (token) { /* * directives */ case T_DOT_ALIGN: return parse_dot_align(stmt, 0 | (0 << 1)); case T_DOT_BALIGN: return parse_dot_align(stmt, 0 | (0 << 1)); case T_DOT_P2ALIGN: return parse_dot_align(stmt, 1 | (0 << 1)); case T_DOT_ASCII: return parse_string_list(stmt, S_ASCII); case T_DOT_ASCIZ: return parse_string_list(stmt, S_ASCIZ); case T_DOT_BYTE: return parse_expr_list(stmt, S_BYTE); case T_DOT_LONG: return parse_expr_list(stmt, S_LONG); case T_DOT_SHORT: return parse_expr_list(stmt, S_SHORT); case T_DOT_FILE: return parse_string(stmt, S_FILE); case T_DOT_IDENT: return parse_string(stmt, S_IDENT); case T_DOT_POPSECTION: return parse_dot_popsection(stmt); case T_DOT_PREVIOUS: return parse_dot_previous(stmt); case T_DOT_SUBSECTION: return parse_dot_subsection(stmt); case T_DOT_GLOBL: return parse_name_list(stmt, S_GLOBL); case T_DOT_HIDDEN: return parse_name_list(stmt, S_HIDDEN); case T_DOT_INTERNAL: return parse_name_list(stmt, S_INTERNAL); case T_DOT_LOCAL: return parse_name_list(stmt, S_LOCAL); case T_DOT_PROTECTED: return parse_name_list(stmt, S_PROTECTED); case T_DOT_WEAK: return parse_name_list(stmt, S_WEAK); case T_DOT_COMM: return parse_dot_comm(stmt); case T_DOT_ORG: return parse_dot_org(stmt); case T_DOT_SET: return parse_setsize(stmt, S_SET); case T_DOT_SIZE: return parse_setsize(stmt, S_SIZE); case T_DOT_SECTION: return parse_dot_section(stmt, 0); case T_DOT_PUSHSECTION: return parse_dot_section(stmt, 1); case T_DOT_BSS: return parse_oldstyle_section(stmt, ".bss"); case T_DOT_DATA: return parse_oldstyle_section(stmt, ".data"); case T_DOT_RODATA: return parse_oldstyle_section(stmt, ".rodata"); case T_DOT_TEXT: return parse_oldstyle_section(stmt, ".text"); #if 0 case T_DOT_SYMVER: case T_DOT_TYPE: case T_DOT_WEAKREF: #endif /* * other symbols */ case T_SYMBOL: /* start of label, insn, or symbol assignment */ return parse_symbol(stmt, &token_attr); /* * literals */ #if 0 case T_UINTEGER: /* start of local label defn */ #endif /* * misc */ case T_ERROR: return -1; /* diagnostics already emitted by scan.c */ case T_EOF: return 0; case T_NEWLINE: continue; default: error("expected directive, label, or instruction", token, &token_attr); return -1; } } }