C 파일을 토큰으로 분할하려고합니다. 컴파일하는 것이 아니라 분석하는 것입니다. 나는 꽤 똑바로 앞으로해야하고, 정의 된 tokens.l
(또는 이와 비슷한) 파일을 찾기 위해 온라인에서 C의 모든 문법이 이미 정의되었지만 아무것도 찾을 수 없다고 생각했다. 주변에 떠돌아 다니는 어떤 종류의 문법이 있는지 궁금해하고 있었나요?flex에 정의 된 C 토큰 파일이 있습니까?
답변
예, 적어도 one 주위에 있습니다.
편집 : 처리하지 않는 몇 가지 문제가 있기 때문에
, 아마도 그것은 내가 몇 년 전에 쓴 일부 (손으로 쓴) 렉싱 코드를 찾고 가치가있다. 이것은 기본적으로 번역의 1, 2 및 3 단계 만 처리합니다. DIGRAPH를 정의하면 C++ 다이 그래프를 번역 할 일부 코드가 활성화됩니다. 그러나 메모리가 작동하면 실제로 일어날 것보다 일찍 번역 작업을하고 있지만 어쨌든 원하지 않을 것입니다. OTOH, 이것은 심지어 모든 토큰에 가까운 곳을 인식하지 못하도록합니다 - 주로 주석을 주석, 문자 리터럴, 문자열 리터럴 등으로 구분합니다. OTOH, trigraphs, 라인 스플 라이스 등을 처리합니다.
변환 된 텍스트로 파일을 열면 플랫폼의 줄 끝 문자를 줄 바꿈 문자로 새 줄에 기본 변환으로 남겨 두어야한다고 가정합니다.) 모드. 대부분의 경우, 그게 옳은 일이지만, 원본 파일이이 호스트에 대해 일반적인 것보다 다른 줄 끝 시퀀스를 갖는 크로스 컴파일러와 같은 것을 생성하려는 경우이를 변경해야 할 수도 있습니다.
먼저이 모든 것들에 외부 인터페이스를 정의하는 헤더 : 다음
/* get_src.h */
#ifndef GET_SRC_INCLUDED
#define GET_SRC_INCLUDED
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This is the size of the largest token we'll attempt to deal with. If
* you want to deal with bigger tokens, change this, and recompile
* get_src.c. Note that an entire comment is treated as a single token,
* so long comments could overflow this. In case of an overflow, the
* entire comment will be read as a single token, but the part larger
* than this will not be stored.
*/
#define MAX_TOKEN_SIZE 8192
/* `last_token' will contain the text of the most recently read token (comment,
* string literal, or character literal).
*/
extern char last_token[];
/* This is the maximum number of characters that can be put back into a
* file opened with parse_fopen or parse_fdopen.
*/
#define MAX_UNGETS 5
#include <limits.h>
#include <stdio.h>
typedef struct {
FILE *file;
char peeks[MAX_UNGETS];
int last_peek;
} PFILE;
/* Some codes we return to indicate having found various items in the
* source code. ERROR is returned to indicate a newline found in the
* middle of a character or string literal or if a file ends inside a
* comment, or if a character literal contains more than two characters.
*
* Note that this starts at INT_MIN, the most negative number available
* in an int. This keeps these symbols from conflicting with any
* characters read from the file. However, one of these could
* theoretically conflict with EOF. EOF usually -1, and these are far
* more negative than that. However, officially EOF can be any value
* less than 0...
*/
enum {
ERROR = INT_MIN,
COMMENT,
CHAR_LIT,
STR_LIT
};
/* Opens a file for parsing and returns a pointer to a structure which
* can be passed to the other functions in the parser/lexer to identify
* the file being worked with.
*/
PFILE *parse_fopen(char const *name);
/* This corresponds closely to fdopen - it takes a FILE * as its
* only parameter, creates a PFILE structure identifying that file, and
* returns a pointer to that structure.
*/
PFILE *parse_ffopen(FILE *stream);
/* Corresponds to fclose.
*/
int parse_fclose(PFILE *stream);
/* returns characters from `stream' read as C source code. String
* literals, characters literals and comments are each returned as a
* single code from those above. All strings of any kind of whitespace
* are returned as a single space character.
*/
int get_source(PFILE *stream);
/* Basically, these two work just like the normal versions of the same,
* with the minor exception that unget_character can unget more than one
* character.
*/
int get_character(PFILE *stream);
void unget_character(int ch, PFILE *stream);
#ifdef __cplusplus
}
#endif
#endif
그리고 모두의 구현 :
/* get_src.c */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define GET_SOURCE
#include "get_src.h"
static size_t current = 0;
char last_token[MAX_TOKEN_SIZE];
PFILE *parse_fopen(char const *name) {
PFILE *temp = malloc(sizeof(PFILE));
if (NULL != temp) {
temp->file = fopen(name, "r");
memset(temp->peeks, 0, sizeof(temp->peeks));
temp->last_peek = 0;
}
return temp;
}
PFILE *parse_ffopen(FILE *file) {
PFILE *temp = malloc(sizeof(PFILE));
if (NULL != temp) {
temp->file = file;
memset(temp->peeks, 0, sizeof(temp->peeks));
temp->last_peek = 0;
}
return temp;
}
int parse_fclose(PFILE *stream) {
int retval = fclose(stream->file);
free(stream);
return retval;
}
static void addchar(int ch) {
/* adds the passed character to the end of `last_token' */
if (current < sizeof(last_token) -1)
last_token[current++] = (char)ch;
if (current == sizeof(last_token)-1)
last_token[current] = '\0';
}
static void clear(void) {
/* clears the previous token and starts building a new one. */
current = 0;
}
static int read_char(PFILE *stream) {
if (stream->last_peek > 0)
return stream->peeks[--stream->last_peek];
return fgetc(stream->file);
}
void unget_character(int ch, PFILE * stream) {
if (stream->last_peek < sizeof(stream->peeks))
stream->peeks[stream->last_peek++] = ch;
}
static int check_trigraph(PFILE *stream) {
/* Checks for trigraphs and returns the equivalant character if there
* is one. Expects that the leading '?' of the trigraph has already
* been read before this is called.
*/
int ch;
if ('?' != (ch=read_char(stream))) {
unget_character(ch, stream);
return '?';
}
ch = read_char(stream);
switch(ch) {
case '(': return '[';
case ')': return ']';
case '/': return '\\';
case '\'': return '^';
case '<': return '{';
case '>': return '}';
case '!': return '|';
case '-': return '~';
case '=': return '#';
default:
unget_character('?', stream);
unget_character(ch, stream);
return '?';
}
}
#ifdef DIGRAPH
static int check_digraph(PFILE *stream, int first) {
/* Checks for a digraph. The first character of the digraph is
* transmitted as the second parameter, as there are several possible
* first characters of a digraph.
*/
int ch = read_char(stream);
switch(first) {
case '<':
if ('%' == ch)
return '{';
if (':' == ch)
return '[';
break;
case ':':
if ('>' == ch)
return ']';
break;
case '%':
if ('>' == ch)
return '}';
if (':' == ch)
return '#';
break;
}
/* If it's not one of the specific combos above, return the characters
* separately and unchanged by putting the second one back into the
* stream, and returning the first one as-is.
*/
unget_character(ch, stream);
return first;
}
#endif
static int get_char(PFILE *stream) {
/* Gets a single character from the stream with any trigraphs or digraphs converted
* to the single character represented. Note that handling digraphs this early in
* translation isn't really correct (and shouldn't happen in C at all).
*/
int ch = read_char(stream);
if (ch == '?')
return check_trigraph(stream);
#ifdef DIGRAPH
if ((ch == '<' || ch == ':' || ch == '%'))
return check_digraph(stream, ch);
#endif
return ch;
}
int get_character(PFILE *stream) {
/* gets a character from `stream'. Any amount of any kind of whitespace
* is returned as a single space. Escaped new-lines are "eaten" here as well.
*/
int ch;
if (!isspace(ch=get_char(stream)) && ch != '\\')
return ch;
// handle line-slicing
if (ch == '\\') {
ch = get_char(stream);
if (ch == '\n')
ch = get_char(stream);
else {
unget_character(ch, stream);
return ch;
}
}
/* If it's a space, skip over consecutive white-space */
while (isspace(ch) && ('\n' != ch))
ch = get_char(stream);
if ('\n' == ch)
return ch;
/* Then put the non-ws character back */
unget_character(ch, stream);
/* and return a single space character... */
return ' ';
}
static int read_char_lit(PFILE *stream) {
/* This is used internally by `get_source' (below) - it expects the
* opening quote of a character literal to have already been read and
* returns CHAR_LIT or ERROR if there's a newline before a close
* quote is found, or if the character literal contains more than two
* characters after escapes are taken into account.
*/
int ch;
int i;
clear();
addchar('\'');
for (i=0; i<2 && ('\'' != (ch = read_char(stream))); i++) {
addchar(ch);
if (ch == '\n')
return ERROR;
if (ch == '\\') {
ch = get_char(stream);
addchar(ch);
}
}
addchar('\'');
addchar('\0');
if (i > 2)
return ERROR;
return CHAR_LIT;
}
static int read_str_lit(PFILE *stream) {
/* Used internally by get_source. Expects the opening quote of a string
* literal to have already been read. Returns STR_LIT, or ERROR if a
* un-escaped newline is found before the close quote.
*/
int ch;
clear();
addchar('"');
while ('"' != (ch = get_char(stream))) {
if ('\n' == ch || EOF == ch)
return ERROR;
addchar(ch);
if(ch == '\\') {
ch = read_char(stream);
addchar(ch);
}
}
addchar('"');
addchar('\0');
return STR_LIT;
}
static int read_comment(PFILE *stream) {
/* Skips over a comment in stream. Assumes the leading '/' has already
* been read and skips over the body. If we're reading C++ source, skips
* C++ single line comments as well as normal C comments.
*/
int ch;
clear();
ch = get_char(stream);
/* Handle a single line comment.
*/
if ('/' == ch) {
addchar('/');
addchar('/');
while ('\n' != (ch = get_char(stream)))
addchar(ch);
addchar('\0');
return COMMENT;
}
if ('*' != ch) {
unget_character(ch, stream);
return '/';
}
addchar('/');
do {
addchar(ch);
while ('*' !=(ch = get_char(stream)))
if (EOF == ch)
return ERROR;
else
addchar(ch);
addchar(ch);
} while ('/' != (ch=get_char(stream)));
addchar('/');
addchar('\0');
return COMMENT;
}
int get_source(PFILE *stream) {
/* reads and returns a single "item" from the stream. An "item" is a
* comment, a literal or a single character after trigraph and possible
* digraph substitution has taken place.
*/
int ch = get_character(stream);
switch(ch) {
case '\'':
return read_char_lit(stream);
case '"':
return read_str_lit(stream);
case '/':
return read_comment(stream);
default:
return ch;
}
}
#ifdef TEST
int main(int argc, char **argv) {
PFILE *f;
int ch;
if (argc != 2) {
fprintf(stderr, "Usage: get_src <filename>\n");
return EXIT_FAILURE;
}
if (NULL==(f= parse_fopen(argv[1]))) {
fprintf(stderr, "Unable to open: %s\n", argv[1]);
return EXIT_FAILURE;
}
while (EOF!=(ch=get_source(f)))
if (ch < 0)
printf("\n%s\n", last_token);
else
printf("%c", ch);
parse_fclose(f);
return 0;
}
#endif
잘 모르겠어요 얼마나 쉬운/어려운 그것에 대해를 그것을 Flex 기반의 렉서로 통합 할 수있을 것입니다 - Flex가 캐릭터를 읽는 데 사용하는 것을 정의하기위한 일종의 훅을 가지고 있지만, 사용하려고 시도한 적이 없기 때문에, 그것에 대해 더 많이 말하지 마라. (그리고 궁극적으로, 확실하게 접근하는 어떤 것으로도 말할 수 없다. 그것도 존재한다).
그건 간단합니다. C99 (C++) 주석이나 16 진수 부동 소수점 상수 또는 'LL'접미사 또는 다른 C99 기능은 포함하지 않습니다 (모두 놀라운 것은 아니며 마지막 업데이트는 1995 년 임). 백 슬래시 - 줄 바꿈 붙여 넣기 또는 trigraphs를 자명하게 다루지는 않지만, 적어도 일부 이중선을 처리합니다. 그러나 그것은 올바른 방향으로의 커다란 발걸음입니다. –
고마워요, 그게 내가 가진 것에 큰 발전이었습니다. – povey
@Jonathan Leffler : 파서는 사전 처리 된 소스를위한 것이므로 백 슬래시 - 줄 바꿈 붙여 넣기 또는 trigraphs를 처리하지 않는 이유입니다. – caf
- 1. C# 토큰 카운터가 있습니까?
- 2. Flex에 C#의 Path.GetExtension과 동일한 기능이 있습니까?
- 3. jmeter에 대한 변수를 정의하기 위해 미리 정의 된 파일이 있습니까?
- 4. XLinq 암호화 된 파일이 있습니까?
- 5. flex에 액션 스크립트 3이 포함 된 swf
- 6. actionscript 또는 flex에 새로운 라인 상수가 있습니까?
- 7. 예상 된 ";" "{"토큰?
- 8. 예기치 않은 미리 정의 된 매크로 행동 토큰
- 9. Managed C++ 미해결 토큰
- 10. C 카운팅 토큰
- 11. Flex에 동적으로 글꼴을 포함 할 수 있습니까?
- 12. 정의 된 C/C++ 컴파일러 목록
- 13. flex에 대한보고 라이브러리 4
- 14. TextInput Flex에 내용로드?
- 15. ANTLR 용으로 작동하는 C++ 문법 파일이 있습니까?
- 16. Flex에 내장 된 SWF의 크기를 분석하는 방법은 없습니까?
- 17. PHP 토큰 - 사용자 정의 상수 찾기
- 18. Windows Media Player를 flex에 포함하십시오.
- 19. 인용 된 문자열을 토큰 화합니다.
- 20. flashvar를 flex에 전달 4
- 21. Twitter oAuth 요청 토큰 C#
- 22. ANTLR - c/C++에서 토큰 값에 액세스
- 23. 레일즈 토큰 토큰
- 24. 모듈 정의 파일이 지정되지 않았습니다.
- 25. C 문자열 토큰 화 질문
- 26. 보드 게임, 토큰 이동 C#
- 27. 토큰/문자열 입력이 혼합 된 NSTokenField가 가능합니까?
- 28. C 헤더 파일 오류 : 예상 식별자 또는 '('토큰 '앞에'[ '토큰
- 29. .c 파일이 필요합니까?
- 30. 미리 정의 된 #if 기호에는 C#이 있습니까?
gcc 소스를 확인하십시오. – sidyll