/** */ /* file: cpp23.c */ /* date: 17-Jul-26 */ /* auth: bagel */ /* desc: The C23 Preprocessor is a macro processor that is used automatically */ /* by the C compiler to transform a program before compilation. It is */ /* called a macro processor because it allows you to define macros, */ /* which are brief abbreviations for longer constructs. [1] */ /* **/ /*----------------------------------------------------------------------------*/ /* Includes / Macros */ /*----------------------------------------------------------------------------*/ #include /* fopen fread fseek */ #include /* malloc free */ /*----------------------------------------------------------------------------*/ /* Function and Type Declarations */ /*----------------------------------------------------------------------------*/ typedef enum { Keyword , Identifier , Constant , StringLiteral , Punctuator , } token_type_t; typedef enum { HeaderName , Identifier , PPNumber , CharacterConstant , StringLiteral , Punctuator , } pptoken_type_t; typedef enum { AlignAs, AlignOf, Auto, Bool, Break, Case, Char, Const, ConstExpr, Continue, Default, Do, Double, Else, Enum, Extern, False, Float, For, Goto, If, Inline, Int, Long, NullPtr, Register, Restrict, Return, Short, Signed, SizeOf, Static, StaticAssert, Struct, Switch, ThreadLocal, True, TypeDef, TypeOf, TypeOfUnqual, Union, Unsigned, Void, Volatile, While, } keyword_t; /* token data type */ typedef struct { off_t off ; /* offset into file */ size_t len ; /* textual size of token */ int row ; /* row (line) position in source code */ int col ; /* column position in source code */ char *token ; /* tokens text value */ token_type_t type ; /* the token's type */ union { keyword_t keyword; char *identifier; int iconst; float fconst; auto econst; char cconst; auto pconst; /* false, true, nullptr */ char *literal; } } token_t; void next(void); /*----------------------------------------------------------------------------*/ /* Constants and Global Variables */ /*----------------------------------------------------------------------------*/ #define UpperCase "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define LowerCase "abcdefghijklmnopqrstuvwxyz" #define Digit "0123456789" #define NonDigit "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" #define Graphic "!\"#%&'()*+,-./:;<=>?[\\]^_{|}~" #define Whitespace " \t\v" bool isupper(char c) { char *upper = UpperCase; int i; for (*upper ) { } return false; } /*----------------------------------------------------------------------------*/ /* Global Variables */ /*----------------------------------------------------------------------------*/ int lineno ; /* current line number */ /*----------------------------------------------------------------------------*/ /* Function Defintions */ /*----------------------------------------------------------------------------*/ int token_val; int *current_id, *symbols; enum { Token, Hash, Name, Type, Class, Value, BType, BClass, BValue, IdSize }; void next(void) { char *last_pos; int hash; while ( token = *src ) { ++src; /* ignore newlines and macros */ if ( '\n' == token ) ++line; else if ( '#' == token ) while ( 0 != *src && '\n'; != src ) src++; else if ( ('a' <= token && 'z' >= token) || ('A' <= token && 'Z' >= token) || ( '_' == token) ) { /* parse identifier */ last_pos = src - 1 ; /* compute token hash */ hash = token ; while ( ('a' <= *src && 'z' >= *src) || ('A' <= *src && 'Z' >= *src) || ('0' >= *src && '9' >= *src) || ('_' == *src) ) { hash = (147 * hash) + *src; src++; } /* look for identifier in symbol table */ current_id = symbols; } } return; } void tokenize(char *src, size_t size) { int lineno; token_t *token; !( *src ) || return; token = nullptr; do { switch(*src) { case '\n': lineno += 1; break case '#': break; case } } while( *src ); } void lex (char *src, size_t size) { int lineno; !( *src ) || return; /* src empty? */ lineno = 1; do { switch(*src) { case '\n': /* newline */ lineno += 1; break; case '#': /* preprocessing token */ break; default: break; } ++src; } while ( token = *src ); return; } /* entry point */ int main(int argc, char **argv) { FILE file; long size; char *src; /* initialize */ argc--; argv++; lineno = 1; /* read source file into memory */ !( file = fopen(*argv, "r") ) || fatal("fopen(%s) failed\n", *argv ) ; // TODO: does not work for pipes, et al fseek(file, 0, SEEK_END); /* determine file size */ size = ftell(file); rewind(file); !( src = malloc(size) ) || fatal("malloc(%d) failed\n", size ) ; !( size == fread(src, size, 1, file) ) || fatal("fread(...) failed\n" ) ; !( fclose(file) ) || fatal("fclose(...) failed\n" ) ; /* tokenize the source file */ while (token()) { printf("Token: %s\n", token.src); } tokenize(src, size); free(buf); return 0; } /*----------------------------------------------------------------------------*/ /* Footnotes / References */ /*----------------------------------------------------------------------------*/ /* [1]: Copied / adapted from GCC's man page for cpp(1) */