/* * GAS like assembler for TCC * * Copyright (c) 2001-2004 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "tcc.h" #ifdef CONFIG_TCC_ASM ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) { char buf[64]; TokenSym *ts; snprintf(buf, sizeof(buf), "L..%u", n); ts = tok_alloc(buf, strlen(buf)); return ts->tok; } ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); static Sym sym_dot; /* Return a symbol we can use inside the assembler, having name NAME. The assembler symbol table is different from the C symbol table (and the Sym members are used differently). But we must be able to look up file-global C symbols from inside the assembler, e.g. for global asm blocks to be able to refer to defined C symbols. This routine gives back either an existing asm-internal symbol, or a new one. In the latter case the new asm-internal symbol is initialized with info from the C symbol table. If CSYM is non-null we take symbol info from it, otherwise we look up NAME in the C symbol table and use that. */ ST_FUNC Sym* get_asm_sym(int name, Sym *csym) { Sym *sym = label_find(name); if (!sym) { sym = label_push(&tcc_state->asm_labels, name, 0); sym->type.t = VT_VOID | VT_EXTERN; if (!csym) { csym = sym_find(name); /* We might be called for an asm block from inside a C routine and so might have local decls on the identifier stack. Search for the first global one. */ while (csym && csym->sym_scope) csym = csym->prev_tok; } /* Now, if we have a defined global symbol copy over section and offset. */ if (csym && ((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) && csym->c) { ElfW(Sym) *esym; esym = &((ElfW(Sym) *)symtab_section->data)[csym->c]; sym->c = csym->c; sym->r = esym->st_shndx; sym->jnext = esym->st_value; /* XXX can't yet store st_size anywhere. */ sym->type.t &= ~VT_EXTERN; /* Mark that this asm symbol doesn't need to be fed back. */ sym->a.dllimport = 1; } else { sym->type.t |= VT_STATIC; } } return sym; } /* We do not use the C expression parser to handle symbols. Maybe the C expression parser could be tweaked to do so. */ static void asm_expr_unary(TCCState *s1, ExprValue *pe) { Sym *sym; int op, label; uint64_t n; const char *p; switch(tok) { case TOK_PPNUM: p = tokc.str.data; n = strtoull(p, (char **)&p, 0); if (*p == 'b' || *p == 'f') { /* backward or forward label */ label = asm_get_local_label_name(s1, n); sym = label_find(label); if (*p == 'b') { /* backward : find the last corresponding defined label */ if (sym && sym->r == 0) sym = sym->prev_tok; if (!sym) tcc_error("local label '%d' not found backward", n); } else { /* forward */ if (!sym || sym->r) { /* if the last label is defined, then define a new one */ sym = label_push(&s1->asm_labels, label, 0); sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN; } } pe->v = 0; pe->sym = sym; pe->pcrel = 0; } else if (*p == '\0') { pe->v = n; pe->sym = NULL; pe->pcrel = 0; } else { tcc_error("invalid number syntax"); } next(); break; case '+': next(); asm_expr_unary(s1, pe); break; case '-': case '~': op = tok; next(); asm_expr_unary(s1, pe); if (pe->sym) tcc_error("invalid operation with label"); if (op == '-') pe->v = -pe->v; else pe->v = ~pe->v; break; case TOK_CCHAR: case TOK_LCHAR: pe->v = tokc.i; pe->sym = NULL; pe->pcrel = 0; next(); break; case '(': next(); asm_expr(s1, pe); skip(')'); break; case '.': pe->v = 0; pe->sym = &sym_dot; pe->pcrel = 0; sym_dot.type.t = VT_VOID | VT_STATIC; sym_dot.r = cur_text_section->sh_num; sym_dot.jnext = ind; next(); break; default: if (tok >= TOK_IDENT) { /* label case : if the label was not found, add one */ sym = get_asm_sym(tok, NULL); if (sym->r == SHN_ABS) { /* if absolute symbol, no need to put a symbol value */ pe->v = sym->jnext; pe->sym = NULL; pe->pcrel = 0; } else { pe->v = 0; pe->sym = sym; pe->pcrel = 0; } next(); } else { tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); } break; } } static void asm_expr_prod(TCCState *s1, ExprValue *pe) { int op; ExprValue e2; asm_expr_unary(s1, pe); for(;;) { op = tok; if (op != '*' && op != '/' && op != '%' && op != TOK_SHL && op != TOK_SAR) break; next(); asm_expr_unary(s1, &e2); if (pe->sym || e2.sym) tcc_error("invalid operation with label"); switch(op) { case '*': pe->v *= e2.v; break; case '/': if (e2.v == 0) { div_error: tcc_error("division by zero"); } pe->v /= e2.v; break; case '%': if (e2.v == 0) goto div_error; pe->v %= e2.v; break; case TOK_SHL: pe->v <<= e2.v; break; default: case TOK_SAR: pe->v >>= e2.v; break; } } } static void asm_expr_logic(TCCState *s1, ExprValue *pe) { int op; ExprValue e2; asm_expr_prod(s1, pe); for(;;) { op = tok; if (op != '&' && op != '|' && op != '^') break; next(); asm_expr_prod(s1, &e2); if (pe->sym || e2.sym) tcc_error("invalid operation with label"); switch(op) { case '&': pe->v &= e2.v; break; case '|': pe->v |= e2.v; break; default: case '^': pe->v ^= e2.v; break; } } } static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) { int op; ExprValue e2; asm_expr_logic(s1, pe); for(;;) { op = tok; if (op != '+' && op != '-') break; next(); asm_expr_logic
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the style checker.
import strutils
import options, ast, msgs, idents, lineinfos, wordrecg
const
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen*(line: string, start: int): int =
while start+result < line.len and line[start+result] in Letters:
inc result
proc `=~`(s: string, a: openArray[string]): bool =
for x in a:
if s.startsWith(x): return true
proc beautifyName(s: string, k: TSymKind): string =
# minimal set of rules here for transition:
# GC_ is allowed
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
if allUpper and k in {skConst, skEnumField, skType}: return s
result = newStringOfCap(s.len)
var i = 0
case k
of skType, skGenericParam:
# Types should start with a capital unless builtins like 'int' etc.:
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
"char", "byte", "bool", "openArray", "seq", "array", "void",
"pointer", "float", "csize", "csize_t", "cdouble", "cchar", "cschar",
"cshort", "cu", "nil", "typedesc", "auto", "any",
"range", "openarray", "varargs", "set", "cfloat", "ref", "ptr",
"untyped", "typed", "static", "sink", "lent", "type", "owned"]:
result.add s[i]
else:
result.add toUpperAscii(s[i])
of skConst, skEnumField:
# for 'const' we keep how it's spelt; either upper case or lower case:
result.add s[0]
else:
# as a special rule, don't transform 'L' to 'l'
if s.len == 1 and s[0] == 'L': result.add 'L'
elif '_' in s: result.add(s[i])
else: result.add toLowerAscii(s[0])
inc i
while i < s.len:
if s[i] == '_':
if i > 0 and s[i-1] in {'A'..'Z'}:
# don't skip '_' as it's essential for e.g. 'GC_disable'
result.add('_')
inc i
result.add s[i]
else:
inc i
result.add toUpperAscii(s[i])
elif allUpper:
result.add toLowerAscii(s[i])
else:
result.add s[i]
inc i
proc differ*(line: string, a, b: int, x: string): string =
proc substrEq(s: string, pos, last: int, substr: string): bool =
var i = 0
while i < substr.len and pos+i <= last and s[pos+i] == substr[i]:
inc i
return i == substr.len
let last = min(b, line.len)
result = ""
if not substrEq(line, a, b, x):
let y = line[a..b]
if cmpIgnoreStyle(y, x) == 0:
result = y
proc checkStyle(conf: ConfigRef; cache: IdentCache; info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
let beau = beautifyName(s, k)
if s !=