필요한 것은 상태 저장 렉서입니다. 정규 표현식이 작업을하지 않는 이유는 그룹이 연속적이지 않기 때문입니다.
int a=3,b=5,c=4;
은 여기에서 문자 0..2이 유형 3..3 공간, 4..7 이름, 평등 번호와 쉼표 다시 이름, 평등, 번호 및 쉼표가되고 싶어요. 그건 입니다.
해결책은 유형 선언이 보일 때를 기억하는 것입니다. 은 다음 세미콜론까지 계속되는 새로운 렉서 모드로 들어갑니다. pygments 설명서에서 Changing states을 참조하십시오.
다음은 CFamilyLexer를 사용하고 세 가지 새로운 lexer 상태를 추가하는 솔루션입니다. 그것은 function
상태에있는 동안이 같은 라인을보고 그래서 때
int m = 3 * a + b, x = /* comments ; everywhere */ a * a;
첫째는 소비 :
int
그것은 내가 추가 한 새 규칙과 일치, 그것은 vardecl
상태가되도록 :
m
아 변수 이름! 렉서가 vardecl
상태이므로, 이것은 새로 정의 된 변수입니다. 그것을 NameDecl
토큰으로 내 보냅니다. 그런 다음 varvalue
상태를 입력하십시오.
3
그냥 숫자입니다.
*
그냥 운영자.
a
오 변수의 이름!하지만 이제 우리는 varvalue
상태에 있으므로 은 이 아니며 변수 선언, 그냥 일반적인 변수 참조입니다.
+ b
연산자와 다른 변수 참조.
,
가변 값 m
완전히 선언 됨. vardecl
상태로 돌아갑니다.
x =
새로운 변수 선언.
/* comments ; everywhere */
다른 상태가 스택에 푸시됩니다. 주석 토큰의 경우 등의 의미가있는 경우 ;
과 같은 중요성은 무시됩니다.
a * a
값이 x
입니다.
;
function
상태로 돌아갑니다. 특수 변수 선언 규칙 이 수행됩니다.
from pygments import highlight
from pygments.formatters import HtmlFormatter, TerminalFormatter
from pygments.formatters.terminal import TERMINAL_COLORS
from pygments.lexer import inherit
from pygments.lexers.compiled import CFamilyLexer
from pygments.token import *
# New token type for variable declarations. Red makes them stand out
# on the console.
NameDecl = Token.NameDecl
STANDARD_TYPES[NameDecl] = 'ndec'
TERMINAL_COLORS[NameDecl] = ('red', 'red')
class CDeclLexer(CFamilyLexer):
tokens = {
# Only touch variables declared inside functions.
'function': [
# The obvious fault that is hard to get around is that
# user-defined types won't be cathed by this regexp.
(r'(?<=\s)(bool|int|long|float|short|double|char|unsigned|signed|void|'
r'[a-z_][a-z0-9_]*_t)\b',
Keyword.Type, 'vardecl'),
inherit
],
'vardecl' : [
(r'\s+', Text),
# Comments
(r'/(\\\n)?[*](.|\n)*?[*](\\\n)?/', Comment.Multiline),
(r';', Punctuation, '#pop'),
(r'[~!%^&*+=|?:<>/-]', Operator),
# After the name of the variable has been tokenized enter
# a new mode for the value.
(r'[a-zA-Z_][a-zA-Z0-9_]*', NameDecl, 'varvalue'),
],
'varvalue' : [
(r'\s+', Text),
(r',', Punctuation, '#pop'),
(r';', Punctuation, '#pop:2'),
# Comments
(r'/(\\\n)?[*](.|\n)*?[*](\\\n)?/', Comment.Multiline),
(r'[~!%^&*+=|?:<>/-\[\]]', Operator),
(r'\d+[LlUu]*', Number.Integer),
# Rules for strings and chars.
(r'L?"', String, 'string'),
(r"L?'(\\.|\\[0-7]{1,3}|\\x[a-fA-F0-9]{1,2}|[^\\\'\n])'", String.Char),
(r'[a-zA-Z_][a-zA-Z0-9_]*', Name),
# Getting arrays right is tricky.
(r'{', Punctuation, 'arrvalue'),
],
'arrvalue' : [
(r'\s+', Text),
(r'\d+[LlUu]*', Number.Integer),
(r'}', Punctuation, '#pop'),
(r'[~!%^&*+=|?:<>/-\[\]]', Operator),
(r',', Punctuation),
(r'[a-zA-Z_][a-zA-Z0-9_]*', Name),
(r'{', Punctuation, '#push'),
]
}
code = '''
#include <stdio.h>
void main(int argc, char *argv[])
{
int vec_a, vec_b;
int a = 3, /* Mo;yo */ b=5, c=7;
int m = 3 * a + b, x = /* comments everywhere */ a * a;
char *myst = "hi;there";
char semi = ';';
time_t now = /* Null; */ NULL;
int arr[10] = {1, 2, 9/c};
int foo[][2] = {{1, 2}};
a = b * 9;
c = 77;
d = (int) 99;
}
'''
for formatter in [TerminalFormatter, HtmlFormatter]:
print highlight(code, CDeclLexer(), formatter())