-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation of a preprocessor, handles #ifdef (#254)
- Loading branch information
Showing
8 changed files
with
143 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
module Preprocessor | ||
|
||
open FParsec.Primitives | ||
open FParsec.CharParsers | ||
open FParsec | ||
|
||
open System.Collections.Generic | ||
|
||
type Impl() = | ||
// Dict of macro name to value | ||
let defines = new Dictionary<string, string>() | ||
|
||
// The stack contains information for each nested #if/#ifdef block | ||
// Some true: the condition was true, keep the text | ||
// Some false: the condition was false, delete the text | ||
// None: the condition was not evaluated, keep the text and the #end | ||
let stack = new Stack<bool option>() | ||
|
||
let currentScope () = | ||
if stack.Count = 0 then None | ||
else stack.Peek() | ||
|
||
let enterScope evaluated = | ||
let current = currentScope () | ||
if current = Some false then | ||
stack.Push current | ||
else | ||
stack.Push evaluated | ||
|
||
let keyword s = attempt (pstring s .>> notFollowedBy letter .>> notFollowedBy digit .>> notFollowedBy (pchar '_')) .>> spaces | ||
|
||
let parseIdent = | ||
manyChars (choice [letter; digit]) | ||
|
||
let parseArgs = parse { | ||
let! _ = pchar '(' | ||
let! _ = pchar ')' | ||
return "(args)" | ||
} | ||
|
||
let parseEndLine = manyCharsTill anyChar (followedBy newline) .>> newline | ||
|
||
let parseDefine = parse { | ||
let! _ = keyword "define" | ||
let! name = parseIdent | ||
let! args = opt parseArgs // TODO | ||
do! spaces | ||
let! line = parseEndLine | ||
defines.Add(name, line) | ||
return sprintf "#define %s %s" name line | ||
} | ||
|
||
let parseIfdef = parse { | ||
let! word = keyword "ifdef" <|> keyword "ifndef" | ||
let! ident = parseIdent | ||
do if defines.ContainsKey ident = (word = "ifdef") then | ||
enterScope (Some true) | ||
else | ||
enterScope (Some false) | ||
return "" | ||
} | ||
|
||
let parseEndif = parse { | ||
let! _ = keyword "endif" | ||
let state = stack.Pop() | ||
return if state = None then | ||
"#endif" | ||
else | ||
"" | ||
} | ||
|
||
let parseText = parse { | ||
let! line = parseEndLine | ||
return | ||
if currentScope() = Some false then "" | ||
else line | ||
} | ||
|
||
let parseOther = parseEndLine |>> (fun s -> "#" + s) | ||
|
||
let directive = pchar '#' >>. spaces >>. choice [parseDefine; parseIfdef; parseEndif; parseOther] | ||
|
||
member _.Parse = many (directive <|> parseText) | ||
|
||
let preprocess streamName content = | ||
let impl = new Impl() | ||
let res = runParserOnString impl.Parse () streamName content | ||
match res with | ||
| Success(s,_,_) -> | ||
// printfn "%s\n-------------------------" (String.concat "\n" s) | ||
String.concat "\n" s | ||
| Failure(str, _, _) -> failwithf "Parse error: %s" str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#version 130 | ||
|
||
#define DEF bar | ||
#define foo() bar | ||
|
||
#ifdef DEF | ||
void keep_ifdef() {} | ||
#endif | ||
|
||
#ifdef UNKNOWN | ||
void remove_ifdef() {} | ||
#endif | ||
|
||
#ifdef DEF | ||
# ifdef DEF // nested | ||
# ifdef UNKNOWN | ||
# ifdef DEF | ||
int remove_this_line; | ||
# endif | ||
int remove_this_line_too; | ||
# endif | ||
void keep_nested() {} | ||
# endif | ||
void keep_outernest() {} | ||
#endif | ||
|
||
void end() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#version 130 | ||
|
||
#define DEF bar | ||
|
||
#define foo bar | ||
|
||
void keep_ifdef() | ||
{} | ||
void keep_nested() | ||
{} | ||
void keep_outernest() | ||
{} | ||
void end() | ||
{} |