Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve preprocessor handling #444

Merged
merged 2 commits into from
Oct 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions Cesium.Parser.Tests/PreprocessorTests/PreprocessorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,18 @@ public Task IfNotDefinedLiteral() => DoTest(
#ifndef foo
int foo() { return 0; }
#endif
");

[Fact]
public Task NestedIfNotDefinedLiteral() => DoTest(
@"#define foo main
#ifndef foo1
int foo_included1() { return 0; }
#ifndef foo
int foo() { return 0; }
#endif
int foo_included2() { return 0; }
#endif
");

[Fact]
Expand Down Expand Up @@ -243,6 +255,37 @@ public Task IfExpressionNotEqualsSkippedIfNotMetLiteral() => DoTest(
#if mycondition != 1
int foo() { return 0; }
#endif
");

[Fact]
public Task IfExpressionGreaterOrEquals() => DoTest(
@"#define mycondition 0
#if mycondition >= 0
int foo() { return 0; }
#endif
");

[Fact]
public Task IfExpressionGreaterThen() => DoTest(
@"#define mycondition 0
#if mycondition > 0
int foo() { return 0; }
#endif
");

[Fact]
public Task IfExpressionLessOrEquals() => DoTest(
@"#define mycondition 0
#if mycondition <= 1
int foo() { return 0; }
#endif
");

[Fact]
public Task IfExpressionLessOrEqualsWhenNotDefined() => DoTest(
@"#if mycondition <= 1
int foo() { return 0; }
#endif
");

[Fact]
Expand Down Expand Up @@ -293,6 +336,15 @@ public Task IfExpressionAnd() => DoTest(
#if mycondition && mycondition2
int foo() { return 0; }
#endif
");

[Fact]
public Task IfExpressionAndWithEquality() => DoTest(
@"#define WINAPI_FAMILY_DESKTOP_APP 100
#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
#if WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
int foo() { return 0; }
#endif
");

[Fact]
Expand All @@ -302,5 +354,13 @@ public Task UndefMacro() => DoTest(
#if !(defined mycondition)
int foo() { return 0; }
#endif
");

[Fact]
public Task ErrorInsideNotActiveBranchIsNotSupported() => DoTest(
@"#define WINAPI_FAMILY_DESKTOP_APP 100
#ifndef WINAPI_FAMILY_DESKTOP_APP
#error ""This should never happens""
#endif
");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
int foo() { return 0; }

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
int foo() { return 0; }

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
int foo() { return 0; }

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

int foo_included1() { return 0; }

int foo_included2() { return 0; }

8 changes: 8 additions & 0 deletions Cesium.Preprocessor/BinaryExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ public BinaryExpression(IPreprocessorExpression first, CPreprocessorOperator @op
return firstValue == secondValue ? "1" : "0";
case CPreprocessorOperator.NotEquals:
return firstValue != secondValue ? "1" : "0";
case CPreprocessorOperator.LessOrEqual:
return (firstValue ?? "").CompareTo(secondValue ?? "") <= 0 ? "1" : "0";
case CPreprocessorOperator.GreaterOrEqual:
return (firstValue ?? "").CompareTo(secondValue ?? "") >= 0 ? "1" : "0";
case CPreprocessorOperator.LessThen:
return (firstValue ?? "").CompareTo(secondValue ?? "") < 0 ? "1" : "0";
case CPreprocessorOperator.GreaterThen:
return (firstValue ?? "").CompareTo(secondValue ?? "") > 0 ? "1" : "0";
case CPreprocessorOperator.LogicalAnd:
return (firstValue.AsBoolean() && secondValue.AsBoolean()) ? "1" : "0";
case CPreprocessorOperator.LogicalOr:
Expand Down
44 changes: 36 additions & 8 deletions Cesium.Preprocessor/CPreprocessor.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Diagnostics;
using System.Globalization;
using System.Text;
using Cesium.Core;
Expand All @@ -10,7 +11,8 @@ namespace Cesium.Preprocessor;

public record CPreprocessor(string CompilationUnitPath, ILexer<IToken<CPreprocessorTokenType>> Lexer, IIncludeContext IncludeContext, IMacroContext MacroContext)
{
private bool IncludeTokens = true;
private bool IncludeTokens => IncludeTokensStack.All(includeToken => includeToken);
private Stack<bool> IncludeTokensStack = new();
public async Task<string> ProcessSource()
{
var buffer = new StringBuilder();
Expand All @@ -22,6 +24,22 @@ public async Task<string> ProcessSource()
return buffer.ToString();
}

private void PushIncludeTokensDepth(bool includeTokes)
{
IncludeTokensStack.Push(includeTokes);
}

private void PopIncludeTokensDepth()
{
IncludeTokensStack.Pop();
}

private void SwitchIncludeTokensDepth()
{
var lastItem = IncludeTokensStack.Pop();
this.PushIncludeTokensDepth(!lastItem);
}

private async IAsyncEnumerable<IToken<CPreprocessorTokenType>> GetPreprocessingResults()
{
var newLine = true;
Expand Down Expand Up @@ -311,6 +329,11 @@ IEnumerable<IToken<CPreprocessorTokenType>> ConsumeLineAll()
return Array.Empty<IToken<CPreprocessorTokenType>>();
}

if (!File.Exists(includeFilePath))
{
Console.Error.WriteLine($"Cannot find path to {filePath} during parsing {CompilationUnitPath}");
}

using var reader = IncludeContext.OpenFileStream(includeFilePath);
await foreach (var token in ProcessInclude(includeFilePath, reader))
{
Expand All @@ -337,7 +360,11 @@ IEnumerable<IToken<CPreprocessorTokenType>> ConsumeLineAll()
{
errorText.Append(enumerator.Current.Text);
}
throw new PreprocessorException($"Error: {errorText.ToString().Trim()}");

if (IncludeTokens)
throw new PreprocessorException($"Error: {errorText.ToString().Trim()}");

return Array.Empty<IToken<CPreprocessorTokenType>>();
}
case "define":
{
Expand All @@ -357,31 +384,31 @@ IEnumerable<IToken<CPreprocessorTokenType>> ConsumeLineAll()
{
var identifier = ConsumeNext(PreprocessingToken).Text;
bool includeTokens = MacroContext.TryResolveMacro(identifier, out _, out var macroReplacement);
IncludeTokens = includeTokens;
PushIncludeTokensDepth(includeTokens);
return Array.Empty<IToken<CPreprocessorTokenType>>();
}
case "if":
{
var expressionTokens = ConsumeLine();
bool includeTokens = EvaluateExpression(expressionTokens.ToList());
IncludeTokens = includeTokens;
PushIncludeTokensDepth(includeTokens);
return Array.Empty<IToken<CPreprocessorTokenType>>();
}
case "ifndef":
{
var identifier = ConsumeNext(PreprocessingToken).Text;
bool donotIncludeTokens = MacroContext.TryResolveMacro(identifier, out _, out var macroReplacement);
IncludeTokens = !donotIncludeTokens;
PushIncludeTokensDepth(!donotIncludeTokens);
return Array.Empty<IToken<CPreprocessorTokenType>>();
}
case "endif":
{
IncludeTokens = true;
PopIncludeTokensDepth();
return Array.Empty<IToken<CPreprocessorTokenType>>();
}
case "else":
{
IncludeTokens = !IncludeTokens;
SwitchIncludeTokensDepth();
return Array.Empty<IToken<CPreprocessorTokenType>>();
}
case "pragma":
Expand All @@ -400,7 +427,7 @@ IEnumerable<IToken<CPreprocessorTokenType>> ConsumeLineAll()
$"Preprocessor directive not supported: {keyword.Kind} {keyword.Text}.");
}
}
private bool EvaluateExpression(IEnumerable<IToken<CPreprocessorTokenType>> expressionTokens)
private bool EvaluateExpression(IList<IToken<CPreprocessorTokenType>> expressionTokens)
{
var stream = new EnumerableStream<IToken<CPreprocessorTokenType>>(
expressionTokens.Union(new[] { new Token<CPreprocessorTokenType>(new Range(), "", End) })).ToBuffered();
Expand All @@ -412,6 +439,7 @@ private bool EvaluateExpression(IEnumerable<IToken<CPreprocessorTokenType>> expr
}

var macroExpression = expression.Ok.Value.EvaluateExpression(MacroContext);
Debug.Assert(stream.IsEnd || stream.Peek().Kind == CPreprocessorTokenType.End);
bool includeTokens = macroExpression.AsBoolean();
return includeTokens;
}
Expand Down
8 changes: 8 additions & 0 deletions Cesium.Preprocessor/CPreprocessorExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ private static IPreprocessorExpression MakeIdentifier(ICPreprocessorToken define

[Rule("binary_expression: simple_expression '==' simple_expression")]
[Rule("binary_expression: simple_expression '!=' simple_expression")]
[Rule("binary_expression: simple_expression '<=' simple_expression")]
[Rule("binary_expression: simple_expression '>=' simple_expression")]
[Rule("binary_expression: simple_expression '<' simple_expression")]
[Rule("binary_expression: simple_expression '>' simple_expression")]
[Rule("binary_expression: expression '||' expression")]
[Rule("binary_expression: expression '&&' expression")]
private static BinaryExpression MakeBinaryExpression(IPreprocessorExpression left, ICPreprocessorToken token, IPreprocessorExpression right)
Expand All @@ -47,6 +51,10 @@ private static UnaryExpression MakePrefixExpression(ICPreprocessorToken token, I
{
"==" => CPreprocessorOperator.Equals,
"!=" => CPreprocessorOperator.NotEquals,
"<=" => CPreprocessorOperator.LessOrEqual,
">=" => CPreprocessorOperator.GreaterOrEqual,
"<" => CPreprocessorOperator.LessThen,
">" => CPreprocessorOperator.GreaterThen,
"!" => CPreprocessorOperator.Negation,
"||" => CPreprocessorOperator.LogicalOr,
"&&" => CPreprocessorOperator.LogicalAnd,
Expand Down
4 changes: 4 additions & 0 deletions Cesium.Preprocessor/CPreprocessorOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ internal enum CPreprocessorOperator
{
Equals,
NotEquals,
LessOrEqual,
GreaterOrEqual,
LessThen,
GreaterThen,
Copy link

@ptasev ptasev Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling: LessThan GreaterThan

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for keeping me in check

Negation,
LogicalOr,
LogicalAnd,
Expand Down
2 changes: 1 addition & 1 deletion Cesium.Preprocessor/CPreprocessorTokenType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public enum CPreprocessorTokenType
[Regex("[^ \t\v\f\r\n#;+\\-*/()=!<\",.|&]+")]
PreprocessingToken,

[Regex("[;+\\-*/=!,.|&]+")]
[Regex("([;+\\-*/=!,.|&]+|<=|>=|>|<)")]
Separator,

[Token("(")]
Expand Down
23 changes: 15 additions & 8 deletions Cesium.Preprocessor/IdentifierExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,23 @@ public IdentifierExpression(string identifer)

public string? EvaluateExpression(IMacroContext context)
{
if (context.TryResolveMacro(this.Identifer, out var parameters, out var macroReplacement))
string? lastValue = null;
var searchValue = this.Identifer;
do
{
return macroReplacement.Count == 0 ? string.Empty : macroReplacement[0].Text;
}
if (Regex.IsMatch(searchValue, $"^{Regexes.IntLiteral}$"))
{
return searchValue;
}

if (Regex.IsMatch(this.Identifer, Regexes.IntLiteral))
{
return this.Identifer;
}
if (context.TryResolveMacro(searchValue, out var parameters, out var macroReplacement))
{
searchValue = macroReplacement.SkipWhile(_ => _.Kind == CPreprocessorTokenType.WhiteSpace).FirstOrDefault()?.Text ?? "";
continue;
}

return null;
return lastValue;
}
while (true);
}
}
3 changes: 3 additions & 0 deletions Cesium.Preprocessor/MacroExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ public static bool AsBoolean(this string? macroValue)
if (macroValue == "0")
return false;

if (macroValue is null)
throw new PreprocessorException("Invalid integer constant expression");

if (int.TryParse(macroValue, CultureInfo.InvariantCulture, out _))
return true;

Expand Down
Loading