pmacs3/mode/c.py

211 lines
8.8 KiB
Python
Raw Normal View History

2009-03-29 20:50:27 -04:00
import os.path
from subprocess import Popen, PIPE, STDOUT
2009-03-29 20:50:27 -04:00
from method.shell import Exec
from mode import Fundamental
import tab
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule, OverridePatternRule
from mode.python import StringGrammar2
class CommentGrammar(Grammar):
rules = [
PatternRule(r'data', r'(?:[^\*]|\*(?!/))+'),
]
2007-07-21 11:40:53 -04:00
class ErrorGrammar(Grammar):
rules = [
PatternRule(r'data', r'[^\\\n]+'),
PatternRule('continuation', r'\\\n$'),
]
2009-03-29 20:50:27 -04:00
chr1 = '[a-zA-Z_]'
chr2 = '[a-zA-Z0-9_]'
word = chr1 + chr2 + '*'
2007-07-21 11:40:53 -04:00
class MacroGrammar(Grammar):
rules = [
PatternRule('continuation', r'\\\n$'),
2009-03-29 20:50:27 -04:00
PatternRule('name', '(?<=#define ) *' + word),
PatternRule('name', '(?<=#ifdef ) *' + word),
PatternRule('name', '(?<=#ifndef ) *' + word),
PatternRule('name', '(?<=#undef ) *' + word),
PatternRule('concat', '##' + chr2 + '+'),
PatternRule('quoted', '#' + chr2 + '+'),
PatternMatchRule('x', r'(defined)(\()(' + word + r')(\))',
'function', 'delimiter', 'name', 'delimiter'),
2007-07-21 11:40:53 -04:00
]
class CGrammar(Grammar):
rules = [
2009-03-29 20:50:27 -04:00
PatternRule('spaces', r' +'),
PatternRule(r"delimiter", r"\.|\(|\)|\[|\]|{|}|@|,|:|`|;|=(?!=)|\?|->"),
2009-03-29 20:50:27 -04:00
PatternRule('eol', r"\n$"),
PatternMatchRule('x', r'(struct|enum|union)( +)(' + word + ')',
'builtin', 'spaces', 'type'),
PatternRule('builtin', r"(?:break|case|continue|default|do|else|for|goto|if|return|sizeof|switch|while)(?!" + chr2 + ")"),
PatternRule('builtin', r"(?:signed|register|extern|const|static|enum|struct|typedef|union|unsigned|volatile)(?!" + chr2 + ")"),
PatternRule('type', r"(?:auto|char|double|float|int|long|short|void|volatile)(?!" + chr2 + ")"),
PatternMatchRule('x', '(' + word + ')( +)(\**)(' + word + ')',
'type', 'spaces', 'binop', 'identifier'),
PatternMatchRule('x', '(' + word + ')(\*+)( +)(' + word + ')',
'type', 'binop', 'spaces', 'identifier'),
PatternRule('function', word + r'(?= *\()'),
PatternRule('constant', "[A-Z_][A-Z0-9_]+(?!" + chr2 + ")"),
PatternRule('label', word + '(?=:)'),
RegionRule('error', '# *error', ErrorGrammar, r'\n$'),
RegionRule('macro', '# *(?:assert|cpu|define|elif|else|endif|error|ident|ifdef|ifndef|if|import|include_next|line|machine|pragma_once|pragma|system|unassert|undef|warning)(?!=' + chr2 + ')', MacroGrammar, r'\n$'),
RegionRule('comment', r'/\*', CommentGrammar, r'\*/'),
PatternRule('comment', '//.*$'),
RegionRule('string', '"', StringGrammar2, '"'),
PatternRule(r"float", r"-?[0-9]+\.[0-9]*|-?\.[0-9]+|-?(?:[0-9]|[0-9]+\.[0-9]*|-?\.[0-9]+)[eE][\+-]?[0-9]+"),
PatternRule(r"integer", r"(?:0(?![x0-9])|-?[1-9][0-9]*|0[0-7]+|0[xX][0-9a-fA-F]+)[lL]?"),
PatternRule(r"operator", r"!(?!=)|\+=|-=|\*=|/=|//=|%=|&=\|\^=|>>=|<<=|\*\*="),
2009-03-29 20:50:27 -04:00
PatternRule('operator', r"\+|<>|<<|<=|<|-|>>|>=|>|\*\*|&|\*|\||/|\^|==|//|~|!=|%"),
RegionRule('macrocomment', '#if +(?:0|NULL|FALSE)', Grammar, '#endif'),
PatternRule('char', r"'.'|'\\.'|'\\[0-7]{3}'"),
PatternMatchRule('x', r'(# *include)( +)(.+)(\n|$)',
'macro.start', 'spaces', 'header', 'macro.end'),
PatternRule('identifier', word),
OverridePatternRule('comment', r'/\* *@@:(?P<token>[.a-zA-Z0-9_]+):(?P<mode>[.a-zA-Z0-9_]+) *\*/$'),
OverridePatternRule('comment', r'// *@@:(?P<token>[.a-zA-Z0-9_]+):(?P<mode>[.a-zA-Z0-9_]+) *$'),
2007-07-21 11:40:53 -04:00
]
MacroGrammar.rules.extend(CGrammar.rules)
2008-10-02 12:49:22 -04:00
class CTabber2(tab.StackTabber2):
2008-10-02 16:06:10 -04:00
open_tokens = {'delimiter': {'{': '}', '(': ')', '[': ']'}}
close_tokens = {'delimiter': {'}': '{', ')': '(', ']': '['}}
control_tokens = {'keyword': {'if': 1, 'else': 1, 'while': 1, 'do': 1, 'for': 1}}
end_at_eof = False
end_at_tokens = {'delimiter': {';': 1}}
nocontinue_tokens = {'delimiter': {';': 1}}
start_free_tokens = {'string.start': 'string.end'}
end_free_tokens = {'string.end': 'string.start'}
start_macro_tokens = {'macro.start': 'macro.end'}
end_macro_tokens = {'macro.end': 'macro.start'}
2008-10-02 12:49:22 -04:00
def is_base(self, y):
if y == 0:
return True
tokens = self._get_tokens(y)
# this assumes that people aren't gonna use these macros inside of
# blocks, which is probably ok.
2008-10-02 16:06:10 -04:00
t = tokens[0]
if t.fqname() == 'macro.start' and t.string in ('#define', '#include'):
2008-10-02 12:49:22 -04:00
return True
# detecting function declarations is annoying; this assumes that people
# won't put a variable type and name on different lines, but that they
# might do that for function return type and name.
#
# unfortunately, valid function return types might include any of the
# four types of tokens below
decl = False
for t in tokens:
if t.name in ('keyword', 'identifier', 'structname', 'enumname'):
decl = True
continue
if decl and t.name == 'function':
break
else:
decl = False
break
return decl
def _is_indent(self, t):
return t.name == 'spaces'
def _is_ignored(self, t):
2008-10-04 10:50:55 -04:00
return t.fqname() in ('spaces', 'eol', 'comment', 'comment.start',
'comment.data', 'comment.null', 'comment.end')
2008-10-02 12:49:22 -04:00
2009-03-29 20:50:27 -04:00
class CCheckSyntax(Exec):
2008-04-18 23:32:08 -04:00
'''Build this C program (using the mode's make cmd)'''
show_success = False
args = []
def _execute(self, w, **vargs):
if w.application.config['c.syntax-rel-dir']:
d = os.path.dirname(w.buffer.path)
self._doit(w, w.buffer.path, w.application.config['c.syntax-cmd'],
cmdname='c-check-syntax', cmddir=d)
else:
self._doit(w, w.buffer.path, w.application.config['c.syntax-cmd'],
cmdname='c-check-syntax')
2009-03-29 20:50:27 -04:00
class CMake(Exec):
2008-04-18 23:32:08 -04:00
'''Build this C program (using the mode's make cmd)'''
show_success = False
args = []
def _execute(self, w, **vargs):
if w.application.config['c.make-rel-dir']:
d = os.path.dirname(w.buffer.path)
self._doit(w, w.buffer.path, w.application.config['c.make-cmd'],
cmdname='c-make', cmddir=d)
else:
self._doit(w, w.buffer.path, w.application.config['c.make-cmd'],
cmdname='c-make')
2009-03-29 20:50:27 -04:00
class C(Fundamental):
name = 'C'
extensions = ['.c', '.h', '.cpp']
2008-10-02 12:49:22 -04:00
tabbercls = CTabber2
2007-10-18 17:07:35 -04:00
grammar = CGrammar
2007-07-21 11:40:53 -04:00
opentokens = ('delimiter',)
2007-10-18 17:07:35 -04:00
opentags = {'(': ')', '[': ']', '{': '}'}
2007-07-21 11:40:53 -04:00
closetokens = ('delimiter',)
2007-10-18 17:07:35 -04:00
closetags = {')': '(', ']': '[', '}': '{'}
2009-02-15 12:06:35 -05:00
actions = [CCheckSyntax, CMake]
format = "%(flag)s %(bname)-18s (%(mname)s) %(indent)s %(cursor)s/%(mark)s %(perc)s [%(func)s]"
commentc = '//'
2007-10-18 17:07:35 -04:00
colors = {
'macrocomment.start': ('red', 'default', 'bold'),
'macrocomment.null': ('red', 'default', 'bold'),
'macrocomment.end': ('red', 'default', 'bold'),
'macro': ('blue', 'default', 'bold'),
'macro.start': ('blue', 'default', 'bold'),
'macro.name': ('yellow', 'default', 'bold'),
'macro.null': ('magenta', 'default', 'bold'),
'macro.continued': ('red', 'default', 'bold'),
'macro.delimiter': ('default', 'default', 'bold'),
'macro.concat': ('yellow', 'default', 'bold'),
'macro.quoted': ('yellow', 'default', 'bold'),
'include': ('blue', 'default', 'bold'),
'header': ('green', 'default', 'bold'),
'type': ('cyan', 'default', 'bold'),
'constant': ('yellow', 'default', 'bold'),
'error.start': ('blue', 'default', 'bold'),
'error.data': ('green', 'default', 'bold'),
'error.null': ('green', 'default', 'bold'),
2007-07-21 11:40:53 -04:00
}
config = {
'c.syntax-cmd': "gcc -x c -fsyntax-only %(path)s",
'c.syntax-rel-dir': False,
'c.make-cmd': "make",
'c.make-rel-dir': True,
}
lconfig = {
'ignore-suffix': ['.o'],
}
2009-02-15 12:06:35 -05:00
_bindings = {
2009-03-29 20:50:27 -04:00
'close-paren': (')',),
'close-brace': ('}',),
'close-bracket': (']',),
2009-02-15 12:06:35 -05:00
'c-check-syntax': ('C-c s',),
2009-03-29 20:50:27 -04:00
'c-make': ('C-c C-c',),
2009-02-15 12:06:35 -05:00
}
2009-03-29 20:50:27 -04:00
def get_functions(self): return {}
def get_function_names(self): return []
def get_line_function(self, y): return None
def get_status_names(self):
2009-03-29 20:50:27 -04:00
names = Fundamental.get_status_names(self)
c = self.window.logical_cursor()
names['func'] = self.get_line_function(c.y)
return names
2007-10-19 02:41:33 -04:00
install = C.install