2009-03-29 20:50:27 -04:00
|
|
|
import os.path
|
2008-03-16 16:08:37 -04:00
|
|
|
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
|
2009-03-28 22:20:37 -04:00
|
|
|
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule, OverridePatternRule
|
2008-10-01 16:58:43 -04:00
|
|
|
from mode.python import StringGrammar2
|
|
|
|
|
|
|
|
class CommentGrammar(Grammar):
|
|
|
|
rules = [
|
|
|
|
PatternRule(r'data', r'(?:[^\*]|\*(?!/))+'),
|
|
|
|
]
|
2007-07-21 11:40:53 -04:00
|
|
|
|
2009-03-15 20:46:50 -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 = [
|
2009-03-15 20:46:50 -04:00
|
|
|
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-04-06 02:20:43 -04:00
|
|
|
PatternRule('spaces', r' +'),
|
2009-04-03 12:25:58 -04:00
|
|
|
|
|
|
|
PatternMatchRule('x', r'(\()( *)(' + word + r')(\**)( *)(\))( *)(?=[a-zA-Z0-9_\(])',
|
2009-04-06 02:20:43 -04:00
|
|
|
'delimiter', 'spaces', 'c.type', 'c.operator',
|
|
|
|
'spaces', 'delimiter', 'spaces'),
|
2009-04-03 12:25:58 -04:00
|
|
|
|
2009-04-06 02:20:43 -04:00
|
|
|
PatternRule("delimiter", r"\.|\(|\)|\[|\]|{|}|@|,|:|`|;|=(?!=)|\?|->"),
|
|
|
|
PatternRule('eol', r"\n$"),
|
2009-03-29 20:50:27 -04:00
|
|
|
PatternMatchRule('x', r'(struct|enum|union)( +)(' + word + ')',
|
2009-04-06 02:20:43 -04:00
|
|
|
'c.builtin', 'spaces', 'c.type'),
|
2009-03-29 20:50:27 -04:00
|
|
|
|
2009-04-05 13:05:42 -04:00
|
|
|
PatternRule('c.builtin', r"(?:break|case|continue|default|do|else|for|goto|if|return|sizeof|switch|while)(?!" + chr2 + ")"),
|
|
|
|
PatternRule('c.builtin', r"(?:signed|register|extern|const|static|enum|struct|typedef|union|unsigned|volatile)(?!" + chr2 + ")"),
|
|
|
|
PatternRule('c.type', r"(?:auto|char|double|float|int|long|short|void|volatile)(?!" + chr2 + ")"),
|
2009-03-29 20:50:27 -04:00
|
|
|
|
2009-03-30 09:36:04 -04:00
|
|
|
PatternMatchRule('x', '(' + word + ')( +)(\**)(' + word + ')( *)(\()',
|
2009-04-06 02:20:43 -04:00
|
|
|
'c.type', 'spaces', 'c.operator', 'c.function',
|
|
|
|
'spaces', 'delimiter'),
|
2009-03-30 09:36:04 -04:00
|
|
|
PatternMatchRule('x', '(' + word + ')(\*+)( +)(' + word + ')( *)(\()',
|
2009-04-06 02:20:43 -04:00
|
|
|
'c.type', 'c.operator', 'spaces', 'c.function',
|
|
|
|
'spaces', 'delimiter'),
|
2009-03-30 09:36:04 -04:00
|
|
|
|
2009-03-29 20:50:27 -04:00
|
|
|
PatternMatchRule('x', '(' + word + ')( +)(\**)(' + word + ')',
|
2009-04-06 02:20:43 -04:00
|
|
|
'c.type', 'spaces', 'c.operator', 'c.identifier'),
|
2009-03-29 20:50:27 -04:00
|
|
|
PatternMatchRule('x', '(' + word + ')(\*+)( +)(' + word + ')',
|
2009-04-06 02:20:43 -04:00
|
|
|
'c.type', 'c.operator', 'spaces', 'c.identifier'),
|
2009-03-29 20:50:27 -04:00
|
|
|
|
2009-04-03 12:25:58 -04:00
|
|
|
|
2009-04-05 13:05:42 -04:00
|
|
|
PatternRule('c.function', word + r'(?= *\()'),
|
|
|
|
PatternRule('c.constant', "[A-Z_][A-Z0-9_]+(?!" + chr2 + ")"),
|
|
|
|
PatternRule('c.label', word + '(?=:)'),
|
|
|
|
RegionRule('c.error', '# *error', ErrorGrammar, r'\n$'),
|
|
|
|
RegionRule('c.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('c.comment', r'/\*', CommentGrammar, r'\*/'),
|
|
|
|
PatternRule('c.comment', '//.*$'),
|
|
|
|
RegionRule('c.string', '"', StringGrammar2, '"'),
|
2009-03-20 00:25:20 -04:00
|
|
|
|
2009-04-05 13:05:42 -04:00
|
|
|
PatternRule("c.float", r"-?[0-9]+\.[0-9]*|-?\.[0-9]+|-?(?:[0-9]|[0-9]+\.[0-9]*|-?\.[0-9]+)[eE][\+-]?[0-9]+"),
|
|
|
|
PatternRule("c.integer", r"(?:0(?![x0-9])|-?[1-9][0-9]*|0[0-7]+|0[xX][0-9a-fA-F]+)[lL]?"),
|
2009-03-20 00:25:20 -04:00
|
|
|
|
2009-04-05 13:05:42 -04:00
|
|
|
PatternRule("c.operator", r"!(?!=)|\+=|-=|\*=|/=|//=|%=|&=\|\^=|>>=|<<=|\*\*="),
|
|
|
|
PatternRule('c.operator', r"\+|<>|<<|<=|<|-|>>|>=|>|\*\*|&|\*|\||/|\^|==|//|~|!=|%"),
|
|
|
|
RegionRule('c.macrocomment', '#if +(?:0|NULL|FALSE)', Grammar, '#endif'),
|
|
|
|
PatternRule('c.char', r"'.'|'\\.'|'\\[0-7]{3}'"),
|
2009-03-29 20:50:27 -04:00
|
|
|
PatternMatchRule('x', r'(# *include)( +)(.+)(\n|$)',
|
2009-04-06 02:20:43 -04:00
|
|
|
'c.macro.start', 'spaces', 'c.header', 'c.macro.end'),
|
2009-04-03 17:36:37 -04:00
|
|
|
PatternRule('c.identifier', word),
|
2009-04-05 13:05:42 -04:00
|
|
|
OverridePatternRule('c.comment', r'/\* *@@:(?P<token>[.a-zA-Z0-9_]+):(?P<mode>[.a-zA-Z0-9_]+) *\*/$'),
|
|
|
|
OverridePatternRule('c.comment', r'// *@@:(?P<token>[.a-zA-Z0-9_]+):(?P<mode>[.a-zA-Z0-9_]+) *$'),
|
2007-07-21 11:40:53 -04:00
|
|
|
]
|
|
|
|
|
2009-03-15 20:46:50 -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': {'}': '{', ')': '(', ']': '['}}
|
2009-04-06 02:20:43 -04:00
|
|
|
control_tokens = {'c.keyword': {'if': 1, 'else': 1, 'while': 1, 'do': 1, 'for': 1}}
|
2008-10-02 16:06:10 -04:00
|
|
|
end_at_eof = False
|
|
|
|
end_at_tokens = {'delimiter': {';': 1}}
|
2009-03-30 01:10:25 -04:00
|
|
|
nocontinue_tokens = {'delimiter': {';': 1, ',': 1}}
|
2009-04-06 02:20:43 -04:00
|
|
|
start_free_tokens = {'c.string.start': 'c.string.end'}
|
|
|
|
end_free_tokens = {'c.string.end': 'c.string.start'}
|
|
|
|
start_macro_tokens = {'c.macro.start': 'c.macro.end'}
|
|
|
|
end_macro_tokens = {'c.macro.end': 'c.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]
|
2009-04-06 02:20:43 -04:00
|
|
|
if t.fqmatchs('c.macro.start', '#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:
|
2009-04-06 02:20:43 -04:00
|
|
|
if t.isa('c.keyword', 'c.identifier', 'c.type'):
|
2008-10-02 12:49:22 -04:00
|
|
|
decl = True
|
|
|
|
continue
|
2009-04-06 02:20:43 -04:00
|
|
|
if decl and t.name == 'c.function':
|
2008-10-02 12:49:22 -04:00
|
|
|
break
|
|
|
|
else:
|
|
|
|
decl = False
|
|
|
|
break
|
|
|
|
return decl
|
|
|
|
def _is_indent(self, t):
|
|
|
|
return t.name == 'spaces'
|
|
|
|
def _is_ignored(self, t):
|
2009-04-06 02:20:43 -04:00
|
|
|
return t.fqisa('spaces', 'eol', 'c.comment', 'c.comment.start',
|
|
|
|
'c.comment.data', 'c.comment.null', 'c.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):
|
2009-04-10 23:45:21 -04:00
|
|
|
cmd='C_INCLUDE_PATH=. %s' % w.application.config['c.syntax-cmd']
|
2008-04-18 23:32:08 -04:00
|
|
|
if w.application.config['c.syntax-rel-dir']:
|
2009-04-10 23:45:21 -04:00
|
|
|
self._doit(w, w.buffer.path, cmd, cmdname='c-check-syntax',
|
|
|
|
cmddir=os.path.dirname(w.buffer.path))
|
2008-04-18 23:32:08 -04:00
|
|
|
else:
|
2009-04-10 23:45:21 -04:00
|
|
|
self._doit(w, w.buffer.path, cmd, cmdname='c-check-syntax')
|
2008-04-18 23:32:08 -04:00
|
|
|
|
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):
|
2009-04-10 23:45:21 -04:00
|
|
|
cmd = w.application.config['c.make-cmd'],
|
2008-04-18 23:32:08 -04:00
|
|
|
if w.application.config['c.make-rel-dir']:
|
2009-04-10 23:45:21 -04:00
|
|
|
d = os.path.dirname(w.buffer.path)
|
|
|
|
self._doit(w, w.buffer.path, cmd, cmdname='c-make', cmddir=d)
|
2008-04-18 23:32:08 -04:00
|
|
|
else:
|
2009-04-10 23:45:21 -04:00
|
|
|
self._doit(w, w.buffer.path, cmd, cmdname='c-make')
|
2008-04-18 23:32:08 -04:00
|
|
|
|
2009-03-29 20:50:27 -04:00
|
|
|
class C(Fundamental):
|
2009-03-17 15:24:10 -04:00
|
|
|
name = 'C'
|
2008-06-01 21:38:25 -04:00
|
|
|
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]
|
2009-04-06 02:20:43 -04:00
|
|
|
format = "%(flag)s %(bname)s (%(mname)s) %(indent)s %(cursor)s %(perc)s [%(func)s]"
|
2009-02-15 12:06:35 -05:00
|
|
|
commentc = '//'
|
|
|
|
|
2007-10-18 17:07:35 -04:00
|
|
|
colors = {
|
2009-04-04 01:11:27 -04:00
|
|
|
#'c.identifier': ('yellow', 'default', 'bold'),
|
2009-04-03 17:36:37 -04:00
|
|
|
'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
|
|
|
}
|
2008-03-20 21:58:30 -04:00
|
|
|
config = {
|
2008-03-21 01:32:03 -04:00
|
|
|
'c.syntax-cmd': "gcc -x c -fsyntax-only %(path)s",
|
|
|
|
'c.syntax-rel-dir': False,
|
|
|
|
'c.make-cmd': "make",
|
|
|
|
'c.make-rel-dir': True,
|
2008-03-20 21:58:30 -04:00
|
|
|
}
|
2008-10-15 17:17:16 -04:00
|
|
|
lconfig = {
|
2009-05-27 15:28:04 -04:00
|
|
|
'ignore_suffix': ['.o'],
|
2008-10-15 17:17:16 -04:00
|
|
|
}
|
2008-09-21 01:15:33 -04:00
|
|
|
|
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
|
|
|
}
|
2008-09-21 01:15:33 -04: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
|
2008-09-21 01:15:33 -04:00
|
|
|
def get_status_names(self):
|
2009-03-29 20:50:27 -04:00
|
|
|
names = Fundamental.get_status_names(self)
|
2008-09-21 01:15:33 -04:00
|
|
|
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
|