summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Kaivo <jkk@ung.org>2019-03-13 21:05:34 -0400
committerJakob Kaivo <jkk@ung.org>2019-03-13 21:05:34 -0400
commit39ecba0032be794a1f4d66f61e09e4910270330f (patch)
tree9b68f25a597891afce13825328e837da168dfada
migrate to gitlab
-rw-r--r--Makefile33
-rw-r--r--as/Makefile11
-rw-r--r--as/as.l25
-rw-r--r--as/as.y36
-rw-r--r--as/x86.h38
-rw-r--r--c89.l95
-rw-r--r--c89.y525
-rw-r--r--c99.l15
-rw-r--r--c99.y29
-rw-r--r--trigraph.c53
10 files changed, 860 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4e77ce4
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,33 @@
+.POSIX:
+
+.SILENT: all clean .util.mk
+
+CFLAGS=-std=gnu99 -D_XOPEN_SOURCE=700 -g
+
+all: .util.mk
+ make -f .util.mk --no-print-directory
+
+deps: clean .util.mk
+
+clean:
+ [ -f .util.mk ] && make -k --no-print-directory -f .util.mk clean || true
+ rm -f .util.mk
+
+.util.mk: . Makefile
+ printf '.POSIX:\n\n' > $@
+ printf '.SUFFIXES: .cat .msg\n\n' >> $@
+ printf 'default: all\n\n' >> $@
+ printf 'CFLAGS=$(CFLAGS)\n' >> $@
+ printf 'UTILITY=%s\n' "$$(basename -s .c $$(grep -l ^main *.c | head -n1))" >> $@
+ printf 'SOURCES=%s\n' "$$(ls -1 *.c | tr '\n' ' ')" >> $@
+ printf 'HEADERS=%s\n' "$$(ls -1 *.h 2>/dev/null | tr '\n' ' ')" >> $@
+ printf 'OBJECTS=%s\n' "$$(ls -1 *.c | sed -e 's/\.c$$/.o/' | tr '\n' ' ')" >> $@
+ printf 'L10N=%s\n' "$$(ls -1 *.msg 2>/dev/null | sed -e 's/\.msg$$/\.cat/' | tr '\n' ' ')" >> $@
+ printf 'L11N=' >> $@
+ sed -ne '/^\/\*\*cat/,/cat\*\*\//p;' *.c | head -n1 | awk '{print $$2 ".cat"}' >> $@
+ printf '\n' >> $@
+ printf 'all: $$(UTILITY) $$(L10N)\n\n' >> $@
+ printf '$$(UTILITY): $$(OBJECTS) $$(HEADERS)\n\n' >> $@
+ printf '.msg.cat:\n\tgencat $$@ $$<\n\n' >> $@
+ printf ".c.cat:\n\tsed -ne '/^\/\*\*cat/,/cat\*\*\//p;' $$< | grep -v ^/ | grep -v ^\* | gencat \$$@ -\n\n" >> $@
+ printf 'clean:\n\trm -f *.o $$(L10N) $$(UTILITY)\n\n' >> $@
diff --git a/as/Makefile b/as/Makefile
new file mode 100644
index 0000000..99fe9de
--- /dev/null
+++ b/as/Makefile
@@ -0,0 +1,11 @@
+as: as.yy.o as.tab.o
+ c99 -o $@ as.yy.o as.tab.o -ly -ll
+
+as.yy.c: as.l as.tab.h
+ lex -t as.l > $@
+
+as.tab.h as.tab.c: as.y
+ yacc -d -b as as.y
+
+clean:
+ rm -f as *.o as.yy.c as.tab.c as.tab.h
diff --git a/as/as.l b/as/as.l
new file mode 100644
index 0000000..059b7c3
--- /dev/null
+++ b/as/as.l
@@ -0,0 +1,25 @@
+%{
+#include <inttypes.h>
+#include "as.tab.h"
+%}
+
+NONDIGIT [_a-zA-Z]
+DIGIT [0-9]
+IDENTIFIERS [_a-zA-Z0-9]
+
+%x COMMENT
+
+%%
+
+{DIGIT}+ { yylval.n = strtoumax(yytext, NULL, 10); return NUMBER; }
+
+{NONDIGIT}{IDENTIFIERS}* { yylval.s = yytext; return TOKEN; }
+
+:|,|\. { return yytext[0]; }
+\n { return NEWLINE; }
+
+; { BEGIN COMMENT; }
+<COMMENT>. ;
+<COMMENT>\n { BEGIN INITIAL; return NEWLINE; }
+
+. ;
diff --git a/as/as.y b/as/as.y
new file mode 100644
index 0000000..ed8714f
--- /dev/null
+++ b/as/as.y
@@ -0,0 +1,36 @@
+%{
+#include <inttypes.h>
+%}
+
+%union {
+ char *s;
+ uintmax_t n;
+};
+
+%token<n> NUMBER
+%token<s> TOKEN
+%token NEWLINE
+
+%%
+
+program
+ : /* empty */
+ | instruction NEWLINE
+;
+
+instruction
+ : bare_instruction
+ | TOKEN ':' bare_instruction
+;
+
+bare_instruction
+ : TOKEN
+ | TOKEN operand
+ | TOKEN operand ',' operand
+ | TOKEN operand ',' operand ',' operand
+;
+
+operand
+ : TOKEN
+ | NUMBER
+;
diff --git a/as/x86.h b/as/x86.h
new file mode 100644
index 0000000..56bf639
--- /dev/null
+++ b/as/x86.h
@@ -0,0 +1,38 @@
+struct {
+const char *mnemonic;
+const char *opcode;
+char x32;
+char x64;
+} x86_opcodes[] = {
+{ "aaa", "37", 1, 0 },
+
+{ "aad", "d5 0a", 1, 0 },
+{ "aad imm8", "db ib", 1, 0 },
+
+{ "aam", "d4 0a", 1, 0 },
+{ "aam imm8", "d4 ib", 1, 0 },
+
+{ "aas", "3f" , 1, 0 },
+
+{ "adc al, imm8", "14 ib", 1, 1 },
+{ "adc ax, immm16", "15 iw", 1, 1 },
+{ "adc eax, imm32", "15 id", 1, 1 },
+{ "adc rax, imm32", "rex.w 15 id", 0, 1 },
+{ "adc r/m8, imm8", "80 /2 ib", 1, 1 },
+{ "adc r/m8*, imm8", "rex 80 /2 ib", 0, 1 },
+{ "adc r/m16, imm16", "81 /2 iw", 1, 1 },
+{ "adc r/m32, imm32", "81 /2 id", 1, 1 },
+{ "adc r/m64, imm32", "rex.w 81 /2 id", 0, 1 },
+{ "adc r/m16, imm8", "83 /2 ib", 1, 1 },
+{ "adc r/m32, imm8", "83 /2 ib", 1, 1 },
+{ "adc r/m64, imm8", "rex.w 83 /2 ib", 0, 1 },
+{ "adc r/m8, r8", "10 /r", 1, 1 },
+{ "adc r/m8*, r8*", "rex 10 /r", 0, 1 },
+{ "adc r/m16, r16", "11 /r", 1, 1 },
+{ "adc r/m32, r32", "11 /r", 1, 1 },
+{ "adc r/m64, r64", "rex.w 11 /r", 0, 1 },
+{ "adc r8, r/m8", "12 /r", 1, 1 },
+{ "adc r8*, r/m8*", "rex 12 /r", 0, 1 },
+{ "adc r16, r/m16", "13 /r", 1, 1 },
+{ "adc r32, r/m32", "13 /r", 1, 1 },
+{ "adc r64, r/m64", "rex.w 13 /r", 0, 1 },
diff --git a/c89.l b/c89.l
new file mode 100644
index 0000000..3f16b44
--- /dev/null
+++ b/c89.l
@@ -0,0 +1,95 @@
+%{
+
+%}
+
+DIGIT [0-9]
+UPPER [A-Z]
+LOWER [a-z]
+NONDIGIT [_a-zA-Z]
+
+%%
+ /* keywords */
+"auto" { return AUTO; }
+"break" { return BREAK; }
+"case" { return CASE; }
+"char" { return CHAR; }
+"const" { return CONST; }
+"continue" { return CONTINUE; }
+"default" { return DEFAULT; }
+"do" { return DO; }
+"double" { return DOUBLE; }
+"else" { return ELSE; }
+"enum" { return ENUM; }
+"extern" { return EXTERN; }
+"float" { return FLOAT; }
+"for" { return FOR; }
+"goto" { return GOTO; }
+"if" { return IF; }
+"int" { return INT; }
+"long" { return LONG; }
+"register" { return REGISTER; }
+"return" { return RETURN; }
+"short" { return SHORT; }
+"signed" { return SIGNED; }
+"sizeof" { return SIZEOF; }
+"static" { return STATIC; }
+"struct" { return STRUCT; }
+"switch" { return SWITCH; }
+"typedef" { return TYPEDEF; }
+"union" { return UNION; }
+"unsigned" { return UNSIGNED; }
+"void" { return VOID; }
+"volatile" { return VOLATILE; }
+"while" { return WHILE; }
+
+ /* operators */
+"[" { return LBRACKET; }
+"]" { return RBRACKET; }
+"(" { return LPAREN; }
+")" { return RPAREN; }
+"." { return DOT; }
+"->" { return ARROW; }
+"++" { return INCREMENT; }
+"--" { return DECREMENT; }
+"&" { return AMPERSAND; }
+"*" { return STAR; }
+"+" { return PLUS; }
+"-" { return MINUS; }
+"~" { return TILDE; }
+"!" { return BANG; }
+"/" { return SLASH; }
+"%" { return PERCENT; }
+"<<" { return LSHIFT; }
+">>" { return RSHIFT; }
+"<" { return LESSTHAN; }
+">" { return GREATERTHAN; }
+"<=" { return LESSEQUAL; }
+">=" { return GREATEREQUAL; }
+"==" { return ISEQUAL; }
+"!=" { return NOTEQUAL; }
+"^" { return CARET; }
+"|" { return PIPE; }
+"&&" { return ANDAND; }
+"||" { return OROR; }
+"?" { return QUESTION; }
+":" { return COLON; }
+"=" { return EQUALS; }
+"*=" { return STAREQUALS; }
+"/=" { return SLASHEQUALS; }
+"%=" { return PERCENTEQUALS; }
+"+=" { return PLUSEQUALS; }
+"-=" { return MINUSEQUALS; }
+"<<=" { return LSHIFTEQUALS; }
+">>=" { return RSHIFTEQUALS; }
+"&=" { return ANDEQUALS; }
+"^=" { return CARETEQUALS; }
+"|=" { return PIPEEQUALS; }
+"," { return COMMA; }
+"#" { return HASH; }
+"##" { return HASHHASH; }
+
+ /* additional punctuators */
+"{" { return LBRACE; }
+"}" { return RBRACE; }
+";" { return SEMICOLON; }
+"..." { return DOTDOTDOT; }
diff --git a/c89.y b/c89.y
new file mode 100644
index 0000000..c4e7920
--- /dev/null
+++ b/c89.y
@@ -0,0 +1,525 @@
+%{
+#include <stdio.h>
+
+int yylex(void);
+
+void yyerror(char *str)
+{
+ printf("WUT?: %s\n" str);
+}
+%}
+
+%union {
+}
+
+ /* keywords */
+%token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM EXTERN
+ FLOAT FOR GOTO IF INT LONG REGISTER RETURN SHORT SIGNED SIZEOF STATIC
+ STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE WHILE
+
+ /* operators */
+%token LBRACKET RBRACKET LPAREN RPAREN DOT ARROW INCREMENT DECREMENT AMPERSAND
+ STAR PLUS MINUS TILDE BANG SLASH PERCENT LSHIFT RSHIFT LESSTHAN
+ GREATERTHAN LESSEQUAL GREATEREQUAL ISEQUAL NOTEQUAL CARET PIPE ANDAND
+ OROR QUESTION COLON EQUALS STAREQUALS SLASHEQUALS PERCENTEQUALS
+ PLUSEQUALS MINUSEQUALS LSHIFTEQUALS RSHIFTEQUALS ANDEQUALS CARETEQUALS
+ PIPEEQUALS COMMA HASH HASHHASH
+
+ /* additional punctuators */
+%token LBRACE RBRACE SEMICOLON DOTDOTDOT
+
+%%
+
+primary-expression:
+ identifier
+ | constant
+ | string-literal
+ | LPAREN expression RPAREN
+ ;
+
+postfix-expression:
+ primary-expression
+ | postfix-expression LBRACKET expression RBRACKET
+ | postfix-expression LPAREN argument-expression-list RPAREN
+ | postfix-expression LPRAEN RPAREN
+ | postfix-expression DOT identifier
+ | postfix-expression ARROW identifier
+ | postfix-expression INCREMENT
+ | postfix-expression DECREMENT
+ ;
+
+argument-expression-list:
+ assignment-expression
+ | argument-expression-list COMMA assignment-expression
+ ;
+
+unary-expression:
+ postfix-expression
+ | INCREMENT unary-expression
+ | DECREMENT unary-expression
+ | unary-operator cast-expression
+ | SIZEOF unary-expression
+ | SIZEOF LPAREN type-name RPAREN
+ ;
+
+unary-operator:
+ AMPERSAND
+ | STAR
+ | PLUS
+ | MINUS
+ | TILDE
+ | BANG
+ ;
+
+cast-expression:
+ unary-expression
+ | LPAREN type-name RPAREN cast-expression
+ ;
+
+multiplicative-expression:
+ cast-expression
+ | multiplicative-expression STAR cast-expression
+ | multiplicative-expression SLASH cast-expression
+ | multiplicative-expression PERCENT cast-expression
+ ;
+
+additive-expression:
+ multiplicative-expression
+ | additive-expression PLUS multiplicative-expression
+ | additive-expression MINUS multiplicative-expression
+ ;
+
+shift-expression:
+ additive-expression
+ | shift-expression LSHIFT additive-expression
+ | shift-expression RSHIFT additive-expression
+ ;
+
+relational-expression:
+ shift-expression
+ | relational-expression LESSTHAN shift-expression
+ | relational-expression GREATERTHAN shift-expression
+ | relational-expression LESSEQUAL shift-expression
+ | relational-expression GREATEREQUAL shift-expression
+ ;
+
+equality-expression:
+ relational-expression
+ | equality-expression ISEQUAL relational-expression
+ | equality-expression NOTEQUAL relational-expression
+ ;
+
+AND-expression:
+ equality-expression
+ | AND-expression AMPERSAND equality-expression
+ ;
+
+exclusive-OR-expression:
+ AND-expression
+ | exclusive-OR-expression CARET AND-expression
+ ;
+
+inclusive-OR-expression:
+ exclusive-OR-expression
+ | inclusive-OR-expression PIPE exclusive-OR-expression
+ ;
+
+logical-AND-expression:
+ inclusive-OR-expression
+ | logical-AND-expression ANDAND inclusive-OR-expression
+ ;
+
+logical-OR-expression:
+ logical-AND-expression
+ | logical-OR-expression OROR logical-AND-expression
+ ;
+
+conditional-expression:
+ logical-OR-expression
+ | logical-OR-expression QUESTION expression COLON conditional-expression
+ ;
+
+assignment-expression:
+ conditional-expression
+ | unary-expression assignment-operator assignment-expression
+ ;
+
+assignment-operator:
+ EQUALS
+ | STAREQUALS
+ | SLASHEQUALS
+ | PERCENTEQUALS
+ | PLUSEQUALS
+ | MINUSEQUALS
+ | LSHIFTEQUALS
+ | RSHIFTEQUALS
+ | ANDEQUALS
+ | CARETEQUALS
+ | PIPEEQUALS
+ ;
+
+expression:
+ assignment-expression
+ | expression COMMA assignment-expression
+ ;
+
+constant-expression:
+ conditional-expression
+ ;
+
+declaration:
+ declaration-specifiers SEMICOLON
+ | declaration-specifiers init-declarator-list SEMICOLON
+ ;
+
+declaration-specifiers:
+ storage-class-specifier
+ | storage-class-specifier declaration-specifiers
+ | type-specifier
+ | type-specifier declaration-specifiers
+ | type-qualifier
+ | type-qualifier declaration-specifiers
+ ;
+
+init-declarator-list:
+ init-declarataor
+ | init-declarator-list COMMA init-declarator
+ ;
+
+init-declarator:
+ declarator
+ | declarator EQUALS initializer
+ ;
+
+storage-class-specifier:
+ TYPEDEF
+ | EXTERN
+ | STATIC
+ | AUTO
+ | REGISTER
+ ;
+
+type-specifier:
+ VOID
+ | CHAR
+ | SHORT
+ | INT
+ | LONG
+ | FLOAT
+ | DOUBLE
+ | SIGNED
+ | UNSIGNED
+ | struct-or-union-specifier
+ | enum-specifier
+ | typedef-name
+ ;
+
+struct-or-union-specifier:
+ struct-or-union LBRACE struct-declaration-list RBRACE
+ | struct-or-union identifier LBRACE struct-declaration-list RBRACE
+ | struct-or-union identifier
+ ;
+
+struct-or-union:
+ STRUCT
+ | UNION
+ ;
+
+struct-declaration-list:
+ struct-declaration
+ | struct-declaration-list struct declaration
+ ;
+
+struct-declaration:
+ specifier-qualifier-list struct-declarator-list SEMICOLON
+ ;
+
+specifier-qualifier-list:
+ type-specifier
+ | type-specifier specifier-qualifier-list
+ | type-qualifier
+ | type-qualifier specifier-qualifier-list
+ ;
+
+struct-declarator-list:
+ struct-declarator
+ | struct-declarator-list COMMA struct-declarator
+ ;
+
+struct-declarator:
+ declarator
+ | COMMA constant-expression
+ | declarator COMMA constant-expression
+ ;
+
+enum-specifier:
+ ENUM LBRACE enumerator-list RBRACE
+ | ENUM identifier LBRACE enumerator-list RBRACE
+ | ENUM identifier
+ ;
+
+enumerator-list:
+ enumerator
+ | enumerator-list COMMA enumerator
+ ;
+
+enumerator:
+ enumeration-constant
+ | enumeration-constant EQUALS constant-expression
+ ;
+
+type-qualifier:
+ CONST
+ | VOID
+ ;
+
+declarator:
+ direct-declarator
+ | pointer direct-declarator
+ ;
+
+direct-declarator:
+ identifier
+ | LPAREN declarator RPAREN
+ | direct-declarator LBRACKET RBRACKET
+ | direct-declarator LBRACKET constant-expression RBRACKET
+ | direct-declarator LPAREN parameter-type-list RPAREN
+ | direct-declarator LPAREN RPAREN
+ | direct-declarator LPAREN identifier-list RPAREN
+ ;
+
+pointer:
+ STAR
+ | STAR type-qualifier-list
+ | STAR pointer
+ | STAR type-qualifier-list pointer
+ ;
+
+type-qualifier-list:
+ type-qualifier
+ | type-qualifier-list type-qualifier
+ ;
+
+parameter-type-list:
+ parameter-list
+ | parameter-list COMMA DOTDOTDOT
+ ;
+
+parameter-list:
+ parameter-declaration
+ | parameter-list COMMA parameter-declaration
+ ;
+
+parameter-declaration:
+ declaration-specifiers declarator
+ | declaration-specifiers
+ | declaration-specifiers abstract-declarator
+ ;
+
+identifier-list:
+ identifier
+ | identifier-list COMMA identifier
+ ;
+
+type-name:
+ specifier-qualifier-list
+ | specifier-qualifier-list abstract-declarator
+ ;
+
+abstract-declarator:
+ pointer
+ | direct-abstract-declarator
+ | point direct-abstract-declarator
+ ;
+
+direct-abstract-declarator:
+ LPAREN abstract-declarator RPAREN
+ | LBRACKET RBRACKET
+ | LBRACKET constant-expression RBRACKET
+ | direct-abstract-declarator LBRACKET RBRACKET
+ | direct-abstract-declarator LBRACKET constant-expression RBRACKET
+ | LPAREN RPAREN
+ | LPAREN parameter-type-list RPAREN
+ | direct-abstract-declarator LPAREN RPAREN
+ | direct-abstract-declarator LPAREN parameter-type-list RPAREN
+ ;
+
+typdef-name:
+ identifier
+ ;
+
+initializer:
+ assignment-expression
+ | LBRACE initializer-list RBRACE
+ | LBRACE initializer-list COMMA RBRACE
+ ;
+
+initializer-list:
+ initializer
+ | initializer-list COMMA initializer
+ ;
+
+statement:
+ labeled-statement
+ | compound-statement
+ | expression-statement
+ | selection-statement
+ | iteration-statement
+ | jump-statement
+ ;
+
+labeled-statement:
+ identifier COLON statement
+ | CASE constant-expression COLON statement
+ | DEFAULT COLON statement
+ ;
+
+compound-statement:
+ LBRACE RBRACE
+ | LBRACE declaration-list RBRACE
+ | LBRACE statement-list RBRACE
+ | LBRACE declaration-list statement-list RBRACE
+ ;
+
+declaration-list:
+ declaration
+ | declaration-list declaration
+ ;
+
+statement-list:
+ statement
+ | statement-list statement
+ ;
+
+expression-statement:
+ SEMICOLON
+ | expression SEMICOLON
+ ;
+
+selection-statement:
+ IF LPAREN expression RPAREN statement
+ | IF LPAREN expression RPAREN statement ELSE statement
+ | SWITCH LPAREN expression RPAREN statement
+ ;
+
+iteration-statement:
+ WHILE LPAREN expression RPAREN statement
+ | DO statement WHILE LPAREN expression RPAREN SEMICOLON
+ | FOR LPAREN SEMICOLON SEMICOLON RPAREN statement
+ | FOR LPAREN expression SEMICOLON SEMICOLON RPAREN statement
+ | FOR LPAREN SEMICOLON expression SEMICOLON RPAREN statement
+ | FOR LPAREN SEMICOLON SEMICOLON expression RPAREN statement
+ | FOR LPAREN expression SEMICOLON expression SEMICOLON RPAREN statement
+ | FOR LPAREN SEMICOLON expression SEMICOLON expression RPAREN statement
+ | FOR LPAREN expression SEMICOLON SEMICOLON expression RPAREN statement
+ | FOR LPAREN expression SEMICOLON expression SEMICOLON expression RPAREN statement
+ ;
+
+jump-statement:
+ GOTO identifier SEMICOLON
+ | CONTINUE SEMICOLON
+ | BREAK SEMICOLON
+ | RETURN SEMICOLON
+ | RETURN expression SEMICOLON
+ ;
+
+translation-unit:
+ external-declaration
+ | translation-unit external-declaration
+ ;
+
+external-declaration:
+ function-definition
+ | declaration
+ ;
+
+function-definition:
+ declarator compound-statement
+ | declaration-specifiers declarator compound-statement
+ | declarator declaration-list compound-statement
+ | declaration-specifiers declarator declaration-list compound-statement
+ ;
+
+preprocessing-file:
+ /* optional */
+ | group
+ ;
+
+group:
+ group-part
+ | group group-part
+ ;
+
+group-part:
+ new-line
+ | pp-tokens new-line
+ | if-section
+ | control-line
+ ;
+
+if-section:
+ if-group endif-line
+ | if-group elif-groups endif-line
+ | if-group else-group endif-line
+ | if-group elif-groups else-group endif-line
+ ;
+
+if-group:
+ HASH IF constant-expression new-line
+ | HASH IF constant-expression new-line group
+ | HASH IFDEF identifier new-line
+ | HASH IFDEF identifier new-line group
+ | HASH IFNDEF identifier new-line
+ | HASH IFNDEF identifier new-line group
+ ;
+
+elif-groups:
+ elif-group
+ | elif-groups elif-group
+ ;
+
+elif-group:
+ HASH ELIF constant-expression new-line
+ | HASH ELIF constant-expression new-line group
+ ;
+
+else-group:
+ HASH ELSE new-line
+ | HASH ELSE new-line group
+ ;
+
+endif-line:
+ HASH ENDIF new-line
+ ;
+
+control-line:
+ HASH INCLUDE pp-tokens new-line
+ | HASH DEFINE identifier replacement-list new-line
+ | HASH DEFINE identifier lparen RPAREN replacement-list new-line
+ | HASH DEFINE identifier lparen identifier-list RPAREN replacement-list new-line
+ | HASH UNDEF identifier new-line
+ | HASH LINE pp-tokens new-line
+ | HASH ERROR new-line
+ | HASH ERROR pp-tokens new-line
+ | HASH PRAGMA new-line
+ | HASH PRAGMA pp-tokens new-line
+ | HASH new-line
+ ;
+
+lparen:
+ LPAREN /* without preceding white space */
+ ;
+
+replacement-list:
+ /* optional */
+ | pp-tokens
+ ;
+
+pp-tokens:
+ preprocessing-token
+ | pp-tokens preprocessing-token
+ ;
+
+new-line:
+ NEWLINE
+ ;
diff --git a/c99.l b/c99.l
new file mode 100644
index 0000000..184980d
--- /dev/null
+++ b/c99.l
@@ -0,0 +1,15 @@
+%{
+#include "c99.tab.h"
+%}
+
+%%
+; { printf ("SEMICOLON\n"); return SEMICOLON; }
+"+" { printf ("PLUS\n"); return PLUS; }
+"-" { printf ("MINUS\n"); return MINUS; }
+int { printf ("INT\n"); return INT; }
+"\".*\"" { printf ("string literal:%s\n", yytext); return STRING; }
+[a-zA-z_]+ { printf ("identifier: %s\n", yytext); return IDENTIFIER; }
+"/*[.]**/" { printf ("COMMENT\n"); return COMMENT; }
+%%
+
+int yywrap (void) { return 0; }
diff --git a/c99.y b/c99.y
new file mode 100644
index 0000000..1788c02
--- /dev/null
+++ b/c99.y
@@ -0,0 +1,29 @@
+%{
+int yylex(void);
+void yyerror(char const *);
+%}
+
+%token IDENTIFIER COMMENT
+%token STRING NUMBER
+
+ /* C89 keywords */
+%token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE
+%token ENUM EXTERN FLOAT FOR GOTO IF INT LONG REGISTER
+%token RETURN SHORT SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION
+%token UNSIGNED VOID VOLATILE WHILE
+
+ /* Punctuation */
+%token PLUS MINUS STAR SLASH
+%token COMMA SEMICOLON
+%token QUESTION COLON
+%token LPAREN RPAREN
+%token LBRACE RBRACE
+%token LBRACKET RBRACKET
+
+ /* C99 keywords */
+%token INLINE RESTRICT _BOOL _COMPLEX _IMAGINARY
+
+%%
+
+input: %empty
+ ;
diff --git a/trigraph.c b/trigraph.c
new file mode 100644
index 0000000..b80b198
--- /dev/null
+++ b/trigraph.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ FILE *in = stdin;
+
+ if (argc > 2) {
+ printf("usage: %s [file]\n", argv[0]);
+ return 1;
+ }
+
+ if (argc == 2) {
+ in = fopen(argv[1], "r");
+ if (in == NULL) {
+ perror(argv[1]);
+ return 1;
+ }
+ }
+
+ int c;
+ int q = 0;
+ while ((c = fgetc(in)) != EOF) {
+ if (q == 2) {
+ switch (c) {
+ case '=': putchar('#'); break;
+ case '/': putchar('\\'); break;
+ case '\'': putchar('^'); break;
+ case '(': putchar('['); break;
+ case ')': putchar(']'); break;
+ case '!': putchar('|'); break;
+ case '<': putchar('{'); break;
+ case '>': putchar('}'); break;
+ case '-': putchar('~'); break;
+ case '?': putchar('?'); break;
+
+ default:
+ printf("??%c", c);
+ break;
+ }
+
+ if (c != '?') {
+ q = 0;
+ }
+ } else if (c == '?') {
+ q++;
+ } else {
+ putchar(c);
+ q = 0;
+ }
+ }
+
+ return 0;
+}