This commit is contained in:
Mike Kasianowicz 2014-09-25 23:05:30 -05:00
Родитель 31a5f5a408
Коммит c4dd3abb55
28 изменённых файлов: 5717 добавлений и 0 удалений

72
Argument.cs Normal file
Просмотреть файл

@ -0,0 +1,72 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CppNet {
/**
* A macro argument.
*
* This encapsulates a raw and preprocessed token stream.
*/
internal class Argument : List<Token> {
public const int NO_ARGS = -1;
private List<Token> _expansion;
public Argument() {
this._expansion = null;
}
public void addToken(Token tok) {
Add(tok);
}
internal void expand(Preprocessor p) {
/* Cache expansion. */
if(_expansion == null) {
this._expansion = p.expand(this);
// System.out.println("Expanded arg " + this);
}
}
public Iterator<Token> expansion()
{
return _expansion.iterator();
}
override public String ToString() {
StringBuilder buf = new StringBuilder();
buf.Append("Argument(");
// buf.Append(super.toString());
buf.Append("raw=[ ");
for (int i = 0; i < this.Count; i++)
buf.Append(this[i].getText());
buf.Append(" ];expansion=[ ");
if(_expansion == null)
buf.Append("null");
else
for(int i = 0; i < _expansion.Count; i++)
buf.Append(_expansion[i].getText());
buf.Append(" ])");
return buf.ToString();
}
}
}

74
CppNet.csproj Normal file
Просмотреть файл

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C2FD9262-69F8-4B75-9AB1-FF359C9143E9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CppNet</RootNamespace>
<AssemblyName>CppNet</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Argument.cs" />
<Compile Include="Feature.cs" />
<Compile Include="FileLexerSource.cs" />
<Compile Include="FixedTokenSource.cs" />
<Compile Include="JavaCompat\JavaCompat.cs" />
<Compile Include="JavaFile.cs" />
<Compile Include="JavaFileSystem.cs" />
<Compile Include="JoinReader.cs" />
<Compile Include="LexerException.cs" />
<Compile Include="LexerSource.cs" />
<Compile Include="Macro.cs" />
<Compile Include="MacroTokenSource.cs" />
<Compile Include="Preprocessor.cs" />
<Compile Include="PreprocessorListener.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Source.cs" />
<Compile Include="SourceIterator.cs" />
<Compile Include="State.cs" />
<Compile Include="StringLexerSource.cs" />
<Compile Include="Token.cs" />
<Compile Include="VirtualFile.cs" />
<Compile Include="VirtualFileSystem.cs" />
<Compile Include="Warning.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

153
CppReader.cs Normal file
Просмотреть файл

@ -0,0 +1,153 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.anarres.cpp;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import static org.anarres.cpp.Token.*;
/**
* A Reader wrapper around the Preprocessor.
*
* This is a utility class to provide a transparent {@link Reader}
* which preprocesses the input text.
*
* @see Preprocessor
* @see Reader
*/
public class CppReader extends Reader {
private Preprocessor cpp;
private String token;
private int idx;
public CppReader(final Reader r) {
cpp = new Preprocessor(new LexerSource(r, true) {
@Override
public String getName() {
return "<CppReader Input@" +
System.identityHashCode(r) + ">";
}
});
token = "";
idx = 0;
}
public CppReader(Preprocessor p) {
cpp = p;
token = "";
idx = 0;
}
/**
* Returns the Preprocessor used by this CppReader.
*/
public Preprocessor getPreprocessor() {
return cpp;
}
/**
* Defines the given name as a macro.
*
* This is a convnience method.
*/
public void addMacro(String name)
throws LexerException {
cpp.addMacro(name);
}
/**
* Defines the given name as a macro.
*
* This is a convnience method.
*/
public void addMacro(String name, String value)
throws LexerException {
cpp.addMacro(name, value);
}
private boolean refill()
throws IOException {
try {
assert cpp != null : "cpp is null : was it closed?";
if (token == null)
return false;
while (idx >= token.length()) {
Token tok = cpp.token();
switch (tok.getType()) {
case EOF:
token = null;
return false;
case CCOMMENT:
case CPPCOMMENT:
if (!cpp.getFeature(Feature.KEEPCOMMENTS)) {
token = " ";
break;
}
default:
token = tok.getText();
break;
}
idx = 0;
}
return true;
}
catch (LexerException e) {
/* Never happens.
if (e.getCause() instanceof IOException)
throw (IOException)e.getCause();
*/
IOException ie = new IOException(String.valueOf(e));
ie.initCause(e);
throw ie;
}
}
public int read()
throws IOException {
if (!refill())
return -1;
return token.charAt(idx++);
}
/* XXX Very slow and inefficient. */
public int read(char cbuf[], int off, int len)
throws IOException {
if (token == null)
return -1;
for (int i = 0; i < len; i++) {
int ch = read();
if (ch == -1)
return i;
cbuf[off + i] = (char)ch;
}
return len;
}
public void close()
throws IOException {
if (cpp != null) {
cpp.close();
cpp = null;
}
token = null;
}
}

113
CppTask.cs Normal file
Просмотреть файл

@ -0,0 +1,113 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.anarres.cpp;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.anarres.cpp.LexerException;
import org.anarres.cpp.Preprocessor;
import org.anarres.cpp.Token;
/**
* An ant task for jcpp.
*/
public class CppTask extends Task {
private static class Macro {
private String name;
private String value;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
private File input;
private File output;
private Preprocessor cpp;
public CppTask() {
super();
cpp = new Preprocessor();
}
public void setInput(File input) {
this.input = input;
}
public void setOutput(File output) {
this.output = output;
}
public void addMacro(Macro macro) {
try {
cpp.addMacro(macro.getName(), macro.getValue());
}
catch (LexerException e) {
throw new BuildException(e);
}
}
public void execute() {
FileWriter writer = null;
try {
if (input == null)
throw new BuildException("Input not specified");
if (output == null)
throw new BuildException("Output not specified");
cpp.addInput(this.input);
writer = new FileWriter(this.output);
for (;;) {
Token tok = cpp.token();
if (tok != null && tok.getType() == Token.EOF)
break;
writer.write(tok.getText());
}
}
catch (Exception e) {
throw new BuildException(e);
}
finally {
if (writer != null) {
try {
writer.close();
}
catch (IOException e) {
}
}
}
}
}

49
Feature.cs Normal file
Просмотреть файл

@ -0,0 +1,49 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
namespace CppNet
{
/**
* Features of the Preprocessor, which may be enabled or disabled.
*/
[Flags]
public enum Feature
{
NONE = 0,
/** Supports ANSI digraphs. */
DIGRAPHS = 1 << 0,
/** Supports ANSI trigraphs. */
TRIGRAPHS = 1 << 1,
/** Outputs linemarker tokens. */
LINEMARKERS = 1 << 2,
/** Reports tokens of type INVALID as errors. */
CSYNTAX = 1 << 3,
/** Preserves comments in the lexed output. */
KEEPCOMMENTS = 1 << 4,
/** Preserves comments in the lexed output, even when inactive. */
KEEPALLCOMMENTS = 1 << 5,
VERBOSE = 1 << 6,
DEBUG = 1 << 7,
/** Supports lexing of objective-C. */
OBJCSYNTAX = 1 << 8,
INCLUDENEXT = 1 << 9
}
}

67
FileLexerSource.cs Normal file
Просмотреть файл

@ -0,0 +1,67 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.IO;
namespace CppNet {
/**
* A {@link Source} which lexes a file.
*
* The input is buffered.
*
* @see Source
*/
public class FileLexerSource : LexerSource {
// private File file;
private String path;
/**
* Creates a new Source for lexing the given File.
*
* Preprocessor directives are honoured within the file.
*/
public FileLexerSource(FileInfo file, String path) : base(new StreamReader(file.OpenRead()), true)
{
// this.file = file;
this.path = path;
}
public FileLexerSource(FileInfo file) :
this(file, file.FullName) {
}
public FileLexerSource(String path) :
this(new FileInfo(path)) {
}
override internal String getPath() {
return path;
}
override internal String getName()
{
return getPath();
}
override public string ToString() {
return "file " + path;
}
}
}

57
FixedTokenSource.cs Normal file
Просмотреть файл

@ -0,0 +1,57 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace CppNet {
internal class FixedTokenSource : Source {
private static readonly Token EOF =
new Token(Token.EOF, "<ts-eof>");
private List<Token> tokens;
private int idx;
internal FixedTokenSource(params Token[] tokens) {
this.tokens = new List<Token>(tokens);
this.idx = 0;
}
internal FixedTokenSource(List<Token> tokens) {
this.tokens = tokens;
this.idx = 0;
}
public override Token token() {
if (idx >= tokens.Count)
return EOF;
return tokens[idx++];
}
override public String ToString() {
StringBuilder buf = new StringBuilder();
buf.Append("constant token stream " + tokens);
Source parent = getParent();
if (parent != null)
buf.Append(" in ").Append(parent);
return buf.ToString();
}
}
}

68
InputLexerSource.cs Normal file
Просмотреть файл

@ -0,0 +1,68 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.anarres.cpp;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;
import static org.anarres.cpp.Token.*;
/**
* A {@link Source} which lexes a file.
*
* The input is buffered.
*
* @see Source
*/
public class InputLexerSource extends LexerSource {
/**
* Creates a new Source for lexing the given Reader.
*
* Preprocessor directives are honoured within the file.
*/
public InputLexerSource(InputStream input)
throws IOException {
super(
new BufferedReader(
new InputStreamReader(
input
)
),
true
);
}
@Override
/* pp */ String getPath() {
return "<standard-input>";
}
@Override
/* pp */ String getName() {
return "standard input";
}
public String toString() {
return getPath();
}
}

96
JavaCompat/JavaCompat.cs Normal file
Просмотреть файл

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using boolean = System.Boolean;
//using Set = System.Collections.Generic.HashSet;
//using ArrayList = System.Collections.Generic.List;
//using Map = System.Collections.Generic.Dictionary;
namespace CppNet
{
static class JavaCompat
{
public static StringBuilder append(this StringBuilder bld, object value)
{
return bld.Append(value);
}
public static int length(this string str)
{
return str.Length;
}
public static char charAt(this string str, int i)
{
return str[i];
}
public static T get<T>(this List<T> list, int i)
{
return list[i];
}
public static Iterator<T> iterator<T>(this List<T> list)
{
return new ListIterator<T>(list);
}
public static string toString(this object o)
{
return o.ToString();
}
}
class ListIterator<T> : Iterator<T>
{
List<T> _list;
int _index;
public ListIterator(List<T> list)
{
_list = list;
}
public boolean hasNext()
{
return _index < _list.Count;
}
public T next()
{
return _list[_index++];
}
public void remove()
{
throw new NotImplementedException();
}
}
public interface Closeable
{
void close();
}
public interface Iterable<T>
{
Iterator<T> iterator();
}
public interface Iterator<T>
{
boolean hasNext();
T next();
void remove();
}
public class IllegalStateException : Exception
{
public IllegalStateException(Exception ex) : base("Illegal State", ex) { }
}
}

49
JavaFile.cs Normal file
Просмотреть файл

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace CppNet
{
public class JavaFile : VirtualFile
{
string _path;
public JavaFile(string path)
{
_path = Path.GetFullPath(path);
}
public bool isFile()
{
return File.Exists(_path) && !File.GetAttributes(_path).HasFlag(FileAttributes.Directory);
}
public string getPath()
{
return _path;
}
public string getName()
{
return Path.GetFileName(_path);
}
public VirtualFile getParentFile()
{
return new JavaFile(Path.GetDirectoryName(_path));
}
public VirtualFile getChildFile(string name)
{
return new JavaFile(Path.Combine(_path, name));
}
public Source getSource()
{
return new FileLexerSource(_path);
}
}
}

40
JavaFileSystem.cs Normal file
Просмотреть файл

@ -0,0 +1,40 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.IO;
namespace CppNet
{
/**
* A virtual filesystem implementation using java.io.
*/
public class JavaFileSystem : VirtualFileSystem
{
public VirtualFile getFile(string path)
{
return new JavaFile(path);
}
public VirtualFile getFile(string dir, string name)
{
return new JavaFile(Path.Combine(dir, name));
}
}
}

221
JoinReader.cs Normal file
Просмотреть файл

@ -0,0 +1,221 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.IO;
namespace CppNet
{
internal class JoinReader /* extends Reader */ {
private TextReader _in;
private PreprocessorListener listener;
private LexerSource source;
private bool trigraphs;
private bool warnings;
private int newlines;
private bool flushnl;
private int[] unget;
private int uptr;
public JoinReader(TextReader ain, bool trigraphs)
{
this._in = ain;
this.trigraphs = trigraphs;
this.newlines = 0;
this.flushnl = false;
this.unget = new int[2];
this.uptr = 0;
}
public JoinReader(TextReader ain) :
this(ain, false)
{
}
public void setTrigraphs(bool enable, bool warnings)
{
this.trigraphs = enable;
this.warnings = warnings;
}
internal void init(Preprocessor pp, LexerSource s)
{
this.listener = pp.getListener();
this.source = s;
setTrigraphs(pp.getFeature(Feature.TRIGRAPHS),
pp.getWarning(Warning.TRIGRAPHS));
}
private int __read()
{
if(uptr > 0)
return unget[--uptr];
return _in.Read();
}
private void _unread(int c)
{
if(c != -1)
unget[uptr++] = c;
System.Diagnostics.Debug.Assert(uptr <= unget.Length,
"JoinReader ungets too many characters");
}
protected void warning(String msg)
{
if(source != null)
source.warning(msg);
else
throw new LexerException(msg);
}
private char trigraph(char raw, char repl)
{
if(trigraphs) {
if(warnings)
warning("trigraph ??" + raw + " converted to " + repl);
return repl;
} else {
if(warnings)
warning("trigraph ??" + raw + " ignored");
_unread(raw);
_unread('?');
return '?';
}
}
private int _read()
{
int c = __read();
if(c == '?' && (trigraphs || warnings)) {
int d = __read();
if(d == '?') {
int e = __read();
switch(e) {
case '(': return trigraph('(', '[');
case ')': return trigraph(')', ']');
case '<': return trigraph('<', '{');
case '>': return trigraph('>', '}');
case '=': return trigraph('=', '#');
case '/': return trigraph('/', '\\');
case '\'': return trigraph('\'', '^');
case '!': return trigraph('!', '|');
case '-': return trigraph('-', '~');
}
_unread(e);
}
_unread(d);
}
return c;
}
public int read()
{
if(flushnl) {
if(newlines > 0) {
newlines--;
return '\n';
}
flushnl = false;
}
for(; ; ) {
int c = _read();
switch(c) {
case '\\':
int d = _read();
switch(d) {
case '\n':
newlines++;
continue;
case '\r':
newlines++;
int e = _read();
if(e != '\n')
_unread(e);
continue;
default:
_unread(d);
return c;
}
case '\r':
case '\n':
case '\u2028':
case '\u2029':
case '\u000B':
case '\u000C':
case '\u0085':
flushnl = true;
return c;
case -1:
if(newlines > 0) {
newlines--;
return '\n';
}
goto default;
default:
return c;
}
}
}
public int read(char[] cbuf, int off, int len)
{
for(int i = 0; i < len; i++) {
int ch = read();
if(ch == -1)
return i;
cbuf[off + i] = (char)ch;
}
return len;
}
public void close()
{
if(_in == null) {
return;
}
_in.Close();
}
override public String ToString()
{
return "JoinReader(nl=" + newlines + ")";
}
/*
public static void main(String[] args) throws IOException {
FileReader f = new FileReader(new File(args[0]));
BufferedReader b = new BufferedReader(f);
JoinReader r = new JoinReader(b);
BufferedWriter w = new BufferedWriter(
new java.io.OutputStreamWriter(System.out)
);
int c;
while ((c = r.read()) != -1) {
w.write((char)c);
}
w.close();
}
*/
}
}

32
LexerException.cs Normal file
Просмотреть файл

@ -0,0 +1,32 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
namespace CppNet {
/**
* A preprocessor exception.
*
* Note to users: I don't really like the name of this class. S.
*/
public class LexerException : Exception {
public LexerException(String msg) : base(msg) { }
public LexerException(Exception cause) : base(cause.Message, cause) {}
}
}

809
LexerSource.cs Normal file
Просмотреть файл

@ -0,0 +1,809 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.IO;
using System.Text;
namespace CppNet {
/** Does not handle digraphs. */
public class LexerSource : Source {
static bool isJavaIdentifierStart(int c) {
return char.IsLetter((char)c) || c == '$' || c == '_';
}
static bool isJavaIdentifierPart(int c)
{
return char.IsLetter((char)c) || c == '$' || c == '_' || char.IsDigit((char)c);
}
static bool isIdentifierIgnorable(int c) {
return c >= 0 && c <= 8 ||
c >= 0xE && c <= 0x1B ||
c >= 0x7F && c <= 0x9F ||
char.GetUnicodeCategory((char)c) == System.Globalization.UnicodeCategory.Format;
}
static int digit(char ch, int radix)
{
try {
return Convert.ToInt32(ch.ToString(), radix);
} catch {
return -1;
}
}
private static readonly bool DEBUG = false;
private JoinReader reader;
private bool ppvalid;
private bool bol;
private bool include;
private bool digraphs;
/* Unread. */
private int u0, u1;
private int ucount;
private int line;
private int column;
private int lastcolumn;
private bool cr;
/* ppvalid is:
* false in StringLexerSource,
* true in FileLexerSource */
public LexerSource(TextReader r, bool ppvalid) {
this.reader = new JoinReader(r);
this.ppvalid = ppvalid;
this.bol = true;
this.include = false;
this.digraphs = true;
this.ucount = 0;
this.line = 1;
this.column = 0;
this.lastcolumn = -1;
this.cr = false;
}
override internal void init(Preprocessor pp) {
base.init(pp);
this.digraphs = pp.getFeature(Feature.DIGRAPHS);
this.reader.init(pp, this);
}
override public int getLine() {
return line;
}
override public int getColumn() {
return column;
}
override internal bool isNumbered() {
return true;
}
/* Error handling. */
private void _error(String msg, bool error) {
int _l = line;
int _c = column;
if (_c == 0) {
_c = lastcolumn;
_l--;
}
else {
_c--;
}
if (error)
base.error(_l, _c, msg);
else
base.warning(_l, _c, msg);
}
/* Allow JoinReader to call this. */
internal void error(String msg)
{
_error(msg, true);
}
/* Allow JoinReader to call this. */
internal void warning(String msg) {
_error(msg, false);
}
/* A flag for string handling. */
internal void setInclude(bool b)
{
this.include = b;
}
/*
private bool _isLineSeparator(int c) {
return Character.getType(c) == Character.LINE_SEPARATOR
|| c == -1;
}
*/
/* XXX Move to JoinReader and canonicalise newlines. */
private static bool isLineSeparator(int c) {
switch ((char)c) {
case '\r':
case '\n':
case '\u2028':
case '\u2029':
case '\u000B':
case '\u000C':
case '\u0085':
return true;
default:
return (c == -1);
}
}
private int read() {
System.Diagnostics.Debug.Assert(ucount <= 2, "Illegal ucount: " + ucount);
switch (ucount) {
case 2:
ucount = 1;
return u1;
case 1:
ucount = 0;
return u0;
}
if (reader == null)
return -1;
int c = reader.read();
switch (c) {
case '\r':
cr = true;
line++;
lastcolumn = column;
column = 0;
break;
case '\n':
if (cr) {
cr = false;
break;
}
goto case '\u2028';
/* fallthrough */
case '\u2028':
case '\u2029':
case '\u000B':
case '\u000C':
case '\u0085':
cr = false;
line++;
lastcolumn = column;
column = 0;
break;
default:
cr = false;
column++;
break;
}
/*
if (isLineSeparator(c)) {
line++;
lastcolumn = column;
column = 0;
}
else {
column++;
}
*/
return c;
}
/* You can unget AT MOST one newline. */
private void unread(int c) {
/* XXX Must unread newlines. */
if (c != -1) {
if (isLineSeparator(c)) {
line--;
column = lastcolumn;
cr = false;
}
else {
column--;
}
switch (ucount) {
case 0:
u0 = c;
ucount = 1;
break;
case 1:
u1 = c;
ucount = 2;
break;
default:
throw new InvalidOperationException(
"Cannot unget another character!"
);
}
// reader.unread(c);
}
}
/* Consumes the rest of the current line into an invalid. */
private Token invalid(StringBuilder text, String reason) {
int d = read();
while (!isLineSeparator(d)) {
text.Append((char)d);
d = read();
}
unread(d);
return new Token(Token.INVALID, text.ToString(), reason);
}
private Token ccomment() {
StringBuilder text = new StringBuilder("/*");
int d;
do {
do {
d = read();
text.Append((char)d);
} while (d != '*');
do {
d = read();
text.Append((char)d);
} while (d == '*');
} while (d != '/');
return new Token(Token.CCOMMENT, text.ToString());
}
private Token cppcomment() {
StringBuilder text = new StringBuilder("//");
int d = read();
while (!isLineSeparator(d)) {
text.Append((char)d);
d = read();
}
unread(d);
return new Token(Token.CPPCOMMENT, text.ToString());
}
private int escape(StringBuilder text) {
int d = read();
switch (d) {
case 'a': text.Append('a'); return 0x07;
case 'b': text.Append('b'); return '\b';
case 'f': text.Append('f'); return '\f';
case 'n': text.Append('n'); return '\n';
case 'r': text.Append('r'); return '\r';
case 't': text.Append('t'); return '\t';
case 'v': text.Append('v'); return 0x0b;
case '\\': text.Append('\\'); return '\\';
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
int len = 0;
int val = 0;
do {
val = (val << 3) + digit((char)d, 8);
text.Append((char)d);
d = read();
} while(++len < 3 && digit((char)d, 8) != -1);
unread(d);
return val;
case 'x':
len = 0;
val = 0;
do {
val = (val << 4) + digit((char)d, 16);
text.Append((char)d);
d = read();
} while(++len < 2 && digit((char)d, 16) != -1);
unread(d);
return val;
/* Exclude two cases from the warning. */
case '"': text.Append('"'); return '"';
case '\'': text.Append('\''); return '\'';
default:
warning("Unnecessary escape character " + (char)d);
text.Append((char)d);
return d;
}
}
private Token character() {
StringBuilder text = new StringBuilder("'");
int d = read();
if (d == '\\') {
text.Append('\\');
d = escape(text);
}
else if (isLineSeparator(d)) {
unread(d);
return new Token(Token.INVALID, text.ToString(),
"Unterminated character literal");
}
else if (d == '\'') {
text.Append('\'');
return new Token(Token.INVALID, text.ToString(),
"Empty character literal");
}
else if (char.IsControl((char)d)) {
text.Append('?');
return invalid(text, "Illegal unicode character literal");
}
else {
text.Append((char)d);
}
int e = read();
if (e != '\'') {
// error("Illegal character constant");
/* We consume up to the next ' or the rest of the line. */
for (;;) {
if (isLineSeparator(e)) {
unread(e);
break;
}
text.Append((char)e);
if (e == '\'')
break;
e = read();
}
return new Token(Token.INVALID, text.ToString(),
"Illegal character constant " + text);
}
text.Append('\'');
/* XXX It this a bad cast? */
return new Token(Token.CHARACTER,
text.ToString(), (char)d);
}
private Token String(char open, char close) {
StringBuilder text = new StringBuilder();
text.Append(open);
StringBuilder buf = new StringBuilder();
for (;;) {
int c = read();
if (c == close) {
break;
}
else if (c == '\\') {
text.Append('\\');
if (!include) {
char d = (char)escape(text);
buf.Append(d);
}
}
else if (c == -1) {
unread(c);
// error("End of file in string literal after " + buf);
return new Token(Token.INVALID, text.ToString(),
"End of file in string literal after " + buf);
}
else if (isLineSeparator(c)) {
unread(c);
// error("Unterminated string literal after " + buf);
return new Token(Token.INVALID, text.ToString(),
"Unterminated string literal after " + buf);
}
else {
text.Append((char)c);
buf.Append((char)c);
}
}
text.Append(close);
return new Token(close == '>' ? Token.HEADER : Token.STRING,
text.ToString(), buf.ToString());
}
private Token _number(StringBuilder text, long val, int d) {
int bits = 0;
for (;;) {
/* XXX Error check duplicate bits. */
if (d == 'U' || d == 'u') {
bits |= 1;
text.Append((char)d);
d = read();
}
else if (d == 'L' || d == 'l') {
if ((bits & 4) != 0)
/* XXX warn */ ;
bits |= 2;
text.Append((char)d);
d = read();
}
else if (d == 'I' || d == 'i') {
if ((bits & 2) != 0)
/* XXX warn */ ;
bits |= 4;
text.Append((char)d);
d = read();
}
else if (char.IsLetter((char)d)) {
unread(d);
return new Token(Token.INVALID, text.ToString(),
"Invalid suffix \"" + (char)d +
"\" on numeric constant");
}
else {
unread(d);
return new Token(Token.INTEGER,
text.ToString(), (long)val);
}
}
}
/* We already chewed a zero, so empty is fine. */
private Token number_octal() {
StringBuilder text = new StringBuilder("0");
int d = read();
long val = 0;
while (digit((char)d, 8) != -1) {
val = (val << 3) + digit((char)d, 8);
text.Append((char)d);
d = read();
}
return _number(text, val, d);
}
/* We do not know whether know the first digit is valid. */
private Token number_hex(char x) {
StringBuilder text = new StringBuilder("0");
text.Append(x);
int d = read();
if (digit((char)d, 16) == -1) {
unread(d);
// error("Illegal hexadecimal constant " + (char)d);
return new Token(Token.INVALID, text.ToString(),
"Illegal hexadecimal digit " + (char)d +
" after "+ text);
}
long val = 0;
do {
val = (val << 4) + digit((char)d, 16);
text.Append((char)d);
d = read();
} while (digit((char)d, 16) != -1);
return _number(text, val, d);
}
/* We know we have at least one valid digit, but empty is not
* fine. */
/* XXX This needs a complete rewrite. */
private Token number_decimal(int c) {
StringBuilder text = new StringBuilder((char)c);
int d = c;
long val = 0;
do {
val = val * 10 + digit((char)d, 10);
text.Append((char)d);
d = read();
} while (digit((char)d, 10) != -1);
return _number(text, val, d);
}
private Token identifier(int c) {
StringBuilder text = new StringBuilder();
int d;
text.Append((char)c);
for (;;) {
d = read();
if (isIdentifierIgnorable(d))
;
else if (isJavaIdentifierPart(d))
text.Append((char)d);
else
break;
}
unread(d);
return new Token(Token.IDENTIFIER, text.ToString());
}
private Token whitespace(int c) {
StringBuilder text = new StringBuilder();
int d;
text.Append((char)c);
for (;;) {
d = read();
if (ppvalid && isLineSeparator(d)) /* XXX Ugly. */
break;
if (char.IsWhiteSpace((char)d))
text.Append((char)d);
else
break;
}
unread(d);
return new Token(Token.WHITESPACE, text.ToString());
}
/* No token processed by cond() contains a newline. */
private Token cond(char c, int yes, int no) {
int d = read();
if (c == d)
return new Token(yes);
unread(d);
return new Token(no);
}
public override Token token() {
Token tok = null;
int _l = line;
int _c = column;
int c = read();
int d;
switch (c) {
case '\n':
if (ppvalid) {
bol = true;
if (include) {
tok = new Token(Token.NL, _l, _c, "\n");
}
else {
int nls = 0;
do {
nls++;
d = read();
} while (d == '\n');
unread(d);
char[] text = new char[nls];
for (int i = 0; i < text.Length; i++)
text[i] = '\n';
// Skip the bol = false below.
tok = new Token(Token.NL, _l, _c, new String(text));
}
if (DEBUG)
System.Console.Error.WriteLine("lx: Returning NL: " + tok);
return tok;
}
/* Let it be handled as whitespace. */
break;
case '!':
tok = cond('=', Token.NE, '!');
break;
case '#':
if (bol)
tok = new Token(Token.HASH);
else
tok = cond('#', Token.PASTE, '#');
break;
case '+':
d = read();
if (d == '+')
tok = new Token(Token.INC);
else if (d == '=')
tok = new Token(Token.PLUS_EQ);
else
unread(d);
break;
case '-':
d = read();
if (d == '-')
tok = new Token(Token.DEC);
else if (d == '=')
tok = new Token(Token.SUB_EQ);
else if (d == '>')
tok = new Token(Token.ARROW);
else
unread(d);
break;
case '*':
tok = cond('=', Token.MULT_EQ, '*');
break;
case '/':
d = read();
if (d == '*')
tok = ccomment();
else if (d == '/')
tok = cppcomment();
else if (d == '=')
tok = new Token(Token.DIV_EQ);
else
unread(d);
break;
case '%':
d = read();
if (d == '=')
tok = new Token(Token.MOD_EQ);
else if (digraphs && d == '>')
tok = new Token('}'); // digraph
else if (digraphs && d == ':') {
bool paste = true;
d = read();
if (d != '%') {
unread(d);
tok = new Token('#'); // digraph
paste = false;
}
d = read();
if (d != ':') {
unread(d); // Unread 2 chars here.
unread('%');
tok = new Token('#'); // digraph
paste = false;
}
if(paste) {
tok = new Token(Token.PASTE); // digraph
}
}
else
unread(d);
break;
case ':':
/* :: */
d = read();
if (digraphs && d == '>')
tok = new Token(']'); // digraph
else
unread(d);
break;
case '<':
if (include) {
tok = String('<', '>');
}
else {
d = read();
if (d == '=')
tok = new Token(Token.LE);
else if (d == '<')
tok = cond('=', Token.LSH_EQ, Token.LSH);
else if (digraphs && d == ':')
tok = new Token('['); // digraph
else if (digraphs && d == '%')
tok = new Token('{'); // digraph
else
unread(d);
}
break;
case '=':
tok = cond('=', Token.EQ, '=');
break;
case '>':
d = read();
if (d == '=')
tok = new Token(Token.GE);
else if (d == '>')
tok = cond('=', Token.RSH_EQ, Token.RSH);
else
unread(d);
break;
case '^':
tok = cond('=', Token.XOR_EQ, '^');
break;
case '|':
d = read();
if (d == '=')
tok = new Token(Token.OR_EQ);
else if (d == '|')
tok = cond('=', Token.LOR_EQ, Token.LOR);
else
unread(d);
break;
case '&':
d = read();
if (d == '&')
tok = cond('=', Token.LAND_EQ, Token.LAND);
else if (d == '=')
tok = new Token(Token.AND_EQ);
else
unread(d);
break;
case '.':
d = read();
if (d == '.')
tok = cond('.', Token.ELLIPSIS, Token.RANGE);
else
unread(d);
/* XXX decimal fraction */
break;
case '0':
/* octal or hex */
d = read();
if (d == 'x' || d == 'X')
tok = number_hex((char)d);
else {
unread(d);
tok = number_octal();
}
break;
case '\'':
tok = character();
break;
case '"':
tok = String('"', '"');
break;
case -1:
close();
tok = new Token(Token.EOF, _l, _c, "<eof>");
break;
}
if (tok == null) {
if (char.IsWhiteSpace((char)c)) {
tok = whitespace(c);
}
else if (char.IsDigit((char)c)) {
tok = number_decimal(c);
}
else if (isJavaIdentifierStart(c)) {
tok = identifier(c);
}
else {
tok = new Token(c);
}
}
if (bol) {
switch (tok.getType()) {
case Token.WHITESPACE:
case Token.CCOMMENT:
break;
default:
bol = false;
break;
}
}
tok.setLocation(_l, _c);
if (DEBUG)
System.Console.WriteLine("lx: Returning " + tok);
// (new Exception("here")).printStackTrace(System.out);
return tok;
}
public override void close()
{
if(reader != null) {
reader.close();
reader = null;
}
base.close();
}
}
}

208
Macro.cs Normal file
Просмотреть файл

@ -0,0 +1,208 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CppNet
{
/**
* A macro object.
*
* This encapsulates a name, an argument count, and a token stream
* for replacement. The replacement token stream may contain the
* extra tokens {@link Token#M_ARG} and {@link Token#M_STRING}.
*/
public class Macro
{
private Source source;
private String name;
/* It's an explicit decision to keep these around here. We don't
* need to; the argument token type is M_ARG and the value
* is the index. The strings themselves are only used in
* stringification of the macro, for debugging. */
private List<String> args;
private bool variadic;
private List<Token> tokens;
public Macro(Source source, String name)
{
this.source = source;
this.name = name;
this.args = null;
this.variadic = false;
this.tokens = new List<Token>();
}
public Macro(String name)
: this(null, name)
{
}
/**
* Sets the Source from which this macro was parsed.
*/
public void setSource(Source s)
{
this.source = s;
}
/**
* Returns the Source from which this macro was parsed.
*
* This method may return null if the macro was not parsed
* from a regular file.
*/
public Source getSource()
{
return source;
}
/**
* Returns the name of this macro.
*/
public String getName()
{
return name;
}
/**
* Sets the arguments to this macro.
*/
public void setArgs(List<String> args)
{
this.args = args;
}
/**
* Returns true if this is a function-like macro.
*/
public bool isFunctionLike()
{
return args != null;
}
/**
* Returns the number of arguments to this macro.
*/
public int getArgs()
{
return args.Count;
}
/**
* Sets the variadic flag on this Macro.
*/
public void setVariadic(bool b)
{
this.variadic = b;
}
/**
* Returns true if this is a variadic function-like macro.
*/
public bool isVariadic()
{
return variadic;
}
/**
* Adds a token to the expansion of this macro.
*/
public void addToken(Token tok)
{
this.tokens.Add(tok);
}
/**
* Adds a "paste" operator to the expansion of this macro.
*
* A paste operator causes the next token added to be pasted
* to the previous token when the macro is expanded.
* It is an error for a macro to end with a paste token.
*/
public void addPaste(Token tok)
{
/*
* Given: tok0 ## tok1
* We generate: M_PASTE, tok0, tok1
* This extends as per a stack language:
* tok0 ## tok1 ## tok2 ->
* M_PASTE, tok0, M_PASTE, tok1, tok2
*/
this.tokens.Insert(tokens.Count - 1, tok);
}
internal List<Token> getTokens()
{
return tokens;
}
/* Paste tokens are inserted before the first of the two pasted
* tokens, so it's a kind of bytecode notation. This method
* swaps them around again. We know that there will never be two
* sequential paste tokens, so a bool is sufficient. */
public String getText() {
StringBuilder buf = new StringBuilder();
bool paste = false;
for (int i = 0; i < tokens.Count; i++) {
Token tok = tokens[i];
if (tok.getType() == Token.M_PASTE) {
System.Diagnostics.Debug.Assert(paste == false, "Two sequential pastes.");
paste = true;
continue;
}
else {
buf.Append(tok.getText());
}
if (paste) {
buf.Append(" #" + "# ");
paste = false;
}
// buf.Append(tokens.get(i));
}
return buf.ToString();
}
override public String ToString()
{
StringBuilder buf = new StringBuilder(name);
if(args != null) {
buf.Append('(');
bool first = true;
foreach(String str in args) {
if(!first) {
buf.Append(", ");
} else {
first = false;
}
buf.Append(str);
}
if(isVariadic()) {
buf.Append("...");
}
buf.Append(')');
}
if(tokens.Count != 0) {
buf.Append(" => ").Append(getText());
}
return buf.ToString();
}
}
}

197
MacroTokenSource.cs Normal file
Просмотреть файл

@ -0,0 +1,197 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Text;
using System.Collections.Generic;
using boolean = System.Boolean;
using Debug = System.Diagnostics.Debug;
namespace CppNet {
/* This source should always be active, since we don't expand macros
* in any inactive context. */
internal class MacroTokenSource : Source {
private Macro macro;
private Iterator<Token> tokens; /* Pointer into the macro. */
private List<Argument> args; /* { unexpanded, expanded } */
private Iterator<Token> arg; /* "current expansion" */
internal MacroTokenSource(Macro m, List<Argument> args) {
this.macro = m;
this.tokens = m.getTokens().iterator();
this.args = args;
this.arg = null;
}
override internal boolean isExpanding(Macro m) {
/* When we are expanding an arg, 'this' macro is not
* being expanded, and thus we may re-expand it. */
if (/* XXX this.arg == null && */ this.macro == m)
return true;
return base.isExpanding(m);
}
/* XXX Called from Preprocessor [ugly]. */
internal static void escape(StringBuilder buf, string cs) {
for (int i = 0; i < cs.length(); i++) {
char c = cs.charAt(i);
switch (c) {
case '\\':
buf.append("\\\\");
break;
case '"':
buf.append("\\\"");
break;
case '\n':
buf.append("\\n");
break;
case '\r':
buf.append("\\r");
break;
default:
buf.append(c);
break;
}
}
}
private void concat(StringBuilder buf, Argument arg) {
Iterator<Token> it = arg.iterator();
while (it.hasNext()) {
Token tok = it.next();
buf.append(tok.getText());
}
}
private Token stringify(Token pos, Argument arg) {
StringBuilder buf = new StringBuilder();
concat(buf, arg);
// System.out.println("Concat: " + arg + " -> " + buf);
StringBuilder str = new StringBuilder("\"");
escape(str, buf.ToString());
str.append("\"");
// System.out.println("Escape: " + buf + " -> " + str);
return new Token(Token.STRING,
pos.getLine(), pos.getColumn(),
str.toString(), buf.toString());
}
/* At this point, we have consumed the first M_PASTE.
* @see Macro#addPaste(Token) */
private void paste(Token ptok) {
StringBuilder buf = new StringBuilder();
Token err = null;
/* We know here that arg is null or expired,
* since we cannot paste an expanded arg. */
int count = 2;
for (int i = 0; i < count; i++) {
if (!tokens.hasNext()) {
/* XXX This one really should throw. */
error(ptok.getLine(), ptok.getColumn(),
"Paste at end of expansion");
buf.append(' ').append(ptok.getText());
break;
}
Token tok = tokens.next();
// System.out.println("Paste " + tok);
switch (tok.getType()) {
case Token.M_PASTE:
/* One extra to paste, plus one because the
* paste token didn't count. */
count += 2;
ptok = tok;
break;
case Token.M_ARG:
int idx = (int)tok.getValue();
concat(buf, args.get(idx));
break;
/* XXX Test this. */
case Token.CCOMMENT:
case Token.CPPCOMMENT:
break;
default:
buf.append(tok.getText());
break;
}
}
/* Push and re-lex. */
/*
StringBuilder src = new StringBuilder();
escape(src, buf);
StringLexerSource sl = new StringLexerSource(src.toString());
*/
StringLexerSource sl = new StringLexerSource(buf.toString());
/* XXX Check that concatenation produces a valid token. */
arg = new SourceIterator(sl);
}
override public Token token() {
for (;;) {
/* Deal with lexed tokens first. */
if (arg != null) {
if (arg.hasNext()) {
Token tok2 = arg.next();
/* XXX PASTE -> INVALID. */
Debug.Assert(tok2.getType() != Token.M_PASTE,
"Unexpected paste token");
return tok2;
}
arg = null;
}
if (!tokens.hasNext())
return new Token(Token.EOF, -1, -1, ""); /* End of macro. */
Token tok = tokens.next();
int idx;
switch (tok.getType()) {
case Token.M_STRING:
/* Use the nonexpanded arg. */
idx = (int)tok.getValue();
return stringify(tok, args.get(idx));
case Token.M_ARG:
/* Expand the arg. */
idx = (int)tok.getValue();
// System.out.println("Pushing arg " + args.get(idx));
arg = args.get(idx).expansion();
break;
case Token.M_PASTE:
paste(tok);
break;
default:
return tok;
}
} /* for */
}
override public String ToString() {
StringBuilder buf = new StringBuilder();
buf.Append("expansion of ").Append(macro.getName());
Source parent = getParent();
if (parent != null)
buf.Append(" in ").Append(parent);
return buf.ToString();
}
}
}

2248
Preprocessor.cs Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

86
PreprocessorListener.cs Normal file
Просмотреть файл

@ -0,0 +1,86 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
namespace CppNet {
/**
* A handler for preprocessor events, primarily errors and warnings.
*
* If no PreprocessorListener is installed in a Preprocessor, all
* error and warning events will throw an exception. Installing a
* listener allows more intelligent handling of these events.
*/
public class PreprocessorListener {
private int errors;
private int warnings;
public PreprocessorListener() {
clear();
}
public void clear() {
errors = 0;
warnings = 0;
}
public int getErrors() {
return errors;
}
public int getWarnings() {
return warnings;
}
protected void print(String msg) {
System.Console.Error.WriteLine(msg);
}
/**
* Handles a warning.
*
* The behaviour of this method is defined by the
* implementation. It may simply record the error message, or
* it may throw an exception.
*/
public void handleWarning(Source source, int line, int column,
String msg) {
warnings++;
print(source.getName() + ":" + line + ":" + column +
": warning: " + msg);
}
/**
* Handles an error.
*
* The behaviour of this method is defined by the
* implementation. It may simply record the error message, or
* it may throw an exception.
*/
public void handleError(Source source, int line, int column,
String msg) {
errors++;
print(source.getName() + ":" + line + ":" + column +
": error: " + msg);
}
public void handleSourceChange(Source source, String ev) {
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CppNet")]
[assembly: AssemblyProduct("CppNet")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a972fb74-7a43-4c22-a381-2b8f0f5d7d2c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

298
Source.cs Normal file
Просмотреть файл

@ -0,0 +1,298 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections.Generic;
using boolean = System.Boolean;
namespace CppNet
{
/**
* An input to the Preprocessor.
*
* Inputs may come from Files, Strings or other sources. The
* preprocessor maintains a stack of Sources. Operations such as
* file inclusion or token pasting will push a new source onto
* the Preprocessor stack. Sources pop from the stack when they
* are exhausted; this may be transparent or explicit.
*
* BUG: Error messages are not handled properly.
*/
public abstract class Source : Iterable<Token>, Closeable
{
private Source parent;
private boolean autopop;
private PreprocessorListener listener;
private boolean active;
private boolean werror;
/* LineNumberReader */
/*
// We can't do this, since we would lose the LexerException
private class Itr implements Iterator {
private Token next = null;
private void advance() {
try {
if (next != null)
next = token();
}
catch (IOException e) {
throw new UnsupportedOperationException(
"Failed to advance token iterator: " +
e.getMessage()
);
}
}
public boolean hasNext() {
return next.getType() != EOF;
}
public Token next() {
advance();
Token t = next;
next = null;
return t;
}
public void remove() {
throw new UnsupportedOperationException(
"Cannot remove tokens from a Source."
);
}
}
*/
public Source()
{
this.parent = null;
this.autopop = false;
this.listener = null;
this.active = true;
this.werror = false;
}
/**
* Sets the parent source of this source.
*
* Sources form a singly linked list.
*/
internal void setParent(Source parent, boolean autopop)
{
this.parent = parent;
this.autopop = autopop;
}
/**
* Returns the parent source of this source.
*
* Sources form a singly linked list.
*/
internal Source getParent()
{
return parent;
}
// @OverrideMustInvoke
internal virtual void init(Preprocessor pp)
{
setListener(pp.getListener());
this.werror = pp.getWarnings().HasFlag(Warning.ERROR);
}
/**
* Sets the listener for this Source.
*
* Normally this is set by the Preprocessor when a Source is
* used, but if you are using a Source as a standalone object,
* you may wish to call this.
*/
public void setListener(PreprocessorListener pl)
{
this.listener = pl;
}
/**
* Returns the File currently being lexed.
*
* If this Source is not a {@link FileLexerSource}, then
* it will ask the parent Source, and so forth recursively.
* If no Source on the stack is a FileLexerSource, returns null.
*/
internal virtual String getPath()
{
Source parent = getParent();
if(parent != null)
return parent.getPath();
return null;
}
/**
* Returns the human-readable name of the current Source.
*/
internal virtual String getName()
{
Source parent = getParent();
if(parent != null)
return parent.getName();
return null;
}
/**
* Returns the current line number within this Source.
*/
public virtual int getLine()
{
Source parent = getParent();
if(parent == null)
return 0;
return parent.getLine();
}
/**
* Returns the current column number within this Source.
*/
public virtual int getColumn()
{
Source parent = getParent();
if(parent == null)
return 0;
return parent.getColumn();
}
/**
* Returns true if this Source is expanding the given macro.
*
* This is used to prevent macro recursion.
*/
internal virtual boolean isExpanding(Macro m)
{
Source parent = getParent();
if(parent != null)
return parent.isExpanding(m);
return false;
}
/**
* Returns true if this Source should be transparently popped
* from the input stack.
*
* Examples of such sources are macro expansions.
*/
internal boolean isAutopop()
{
return autopop;
}
/**
* Returns true if this source has line numbers.
*/
internal virtual boolean isNumbered()
{
return false;
}
/* This is an incredibly lazy way of disabling warnings when
* the source is not active. */
internal void setActive(boolean b)
{
this.active = b;
}
internal boolean isActive()
{
return active;
}
/**
* Returns the next Token parsed from this input stream.
*
* @see Token
*/
public abstract Token token();
/**
* Returns a token iterator for this Source.
*/
public Iterator<Token> iterator()
{
return new SourceIterator(this);
}
/**
* Skips tokens until the end of line.
*
* @param white true if only whitespace is permitted on the
* remainder of the line.
* @return the NL token.
*/
public Token skipline(boolean white)
{
for(; ; ) {
Token tok = token();
switch(tok.getType()) {
case Token.EOF:
/* There ought to be a newline before EOF.
* At least, in any skipline context. */
/* XXX Are we sure about this? */
warning(tok.getLine(), tok.getColumn(),
"No newline before end of file");
return new Token(Token.NL,
tok.getLine(), tok.getColumn(),
"\n");
// return tok;
case Token.NL:
/* This may contain one or more newlines. */
return tok;
case Token.CCOMMENT:
case Token.CPPCOMMENT:
case Token.WHITESPACE:
break;
default:
/* XXX Check white, if required. */
if(white)
warning(tok.getLine(), tok.getColumn(),
"Unexpected nonwhite token");
break;
}
}
}
protected void error(int line, int column, String msg)
{
if(listener != null)
listener.handleError(this, line, column, msg);
else
throw new LexerException("Error at " + line + ":" + column + ": " + msg);
}
protected void warning(int line, int column, String msg)
{
if(werror)
error(line, column, msg);
else if(listener != null)
listener.handleWarning(this, line, column, msg);
else
throw new LexerException("Warning at " + line + ":" + column + ": " + msg);
}
public virtual void close()
{
}
}
}

98
SourceIterator.cs Normal file
Просмотреть файл

@ -0,0 +1,98 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.IO;
using boolean = System.Boolean;
namespace CppNet
{
/**
* An Iterator for {@link Source Sources},
* returning {@link Token Tokens}.
*/
public class SourceIterator : Iterator<Token>
{
private Source source;
private Token tok;
public SourceIterator(Source s)
{
this.source = s;
this.tok = null;
}
/**
* Rethrows IOException inside IllegalStateException.
*/
private void advance()
{
try {
if(tok == null)
tok = source.token();
} catch(LexerException e) {
throw new IllegalStateException(e);
} catch(IOException e) {
throw new ApplicationException("",e);
}
}
/**
* Returns true if the enclosed Source has more tokens.
*
* The EOF token is never returned by the iterator.
* @throws IllegalStateException if the Source
* throws a LexerException or IOException
*/
public boolean hasNext()
{
advance();
return tok.getType() != Token.EOF;
}
/**
* Returns the next token from the enclosed Source.
*
* The EOF token is never returned by the iterator.
* @throws IllegalStateException if the Source
* throws a LexerException or IOException
*/
public Token next()
{
if(!hasNext())
throw new ArgumentOutOfRangeException();
Token t = this.tok;
this.tok = null;
return t;
}
/**
* Not supported.
*
* @throws UnsupportedOperationException.
*/
public void remove()
{
throw new NotSupportedException();
}
}
}

89
State.cs Normal file
Просмотреть файл

@ -0,0 +1,89 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
namespace CppNet
{
/* pp */
class State
{
bool _parent;
bool _active;
bool _sawElse;
/* pp */
internal State()
{
this._parent = true;
this._active = true;
this._sawElse = false;
}
/* pp */
internal State(State parent)
{
this._parent = parent.isParentActive() && parent.isActive();
this._active = true;
this._sawElse = false;
}
/* Required for #elif */
/* pp */
internal void setParentActive(bool b)
{
this._parent = b;
}
/* pp */
internal bool isParentActive()
{
return _parent;
}
/* pp */
internal void setActive(bool b)
{
this._active = b;
}
/* pp */
internal bool isActive()
{
return _active;
}
/* pp */
internal void setSawElse()
{
_sawElse = true;
}
/* pp */
internal bool sawElse()
{
return _sawElse;
}
public override String ToString()
{
return "parent=" + _parent +
", active=" + _active +
", sawelse=" + _sawElse;
}
}
}

55
StringLexerSource.cs Normal file
Просмотреть файл

@ -0,0 +1,55 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.IO;
namespace CppNet {
/**
* A Source for lexing a String.
*
* This class is used by token pasting, but can be used by user
* code.
*/
public class StringLexerSource : LexerSource {
/**
* Creates a new Source for lexing the given String.
*
* @param ppvalid true if preprocessor directives are to be
* honoured within the string.
*/
public StringLexerSource(String str, bool ppvalid) :
base(new StringReader(str), ppvalid) {
}
/**
* Creates a new Source for lexing the given String.
*
* By default, preprocessor directives are not honoured within
* the string.
*/
public StringLexerSource(String str) :
this(str, false) {
}
override public String ToString() {
return "string literal";
}
}
}

353
Token.cs Normal file
Просмотреть файл

@ -0,0 +1,353 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Text;
namespace CppNet {
/**
* A Preprocessor token.
*
* @see Preprocessor
*/
public sealed class Token
{
// public const int EOF = -1;
private int type;
private int line;
private int column;
private Object value;
private String text;
public Token(int type, int line, int column,
String text, Object value)
{
this.type = type;
this.line = line;
this.column = column;
this.text = text;
this.value = value;
}
public Token(int type, int line, int column, String text) :
this(type, line, column, text, null)
{
}
/* pp */
internal Token(int type, String text, Object value) :
this(type, -1, -1, text, value)
{
}
/* pp */
internal Token(int type, String text) :
this(type, text, null)
{
}
/* pp */
internal Token(int type) :
this(type, type < _TOKENS ? texts[type] : "TOK" + type)
{
}
/**
* Returns the semantic type of this token.
*/
public int getType()
{
return type;
}
internal void setLocation(int line, int column)
{
this.line = line;
this.column = column;
}
/**
* Returns the line at which this token started.
*
* Lines are numbered from zero.
*/
public int getLine()
{
return line;
}
/**
* Returns the column at which this token started.
*
* Columns are numbered from zero.
*/
public int getColumn()
{
return column;
}
/**
* Returns the original or generated text of this token.
*
* This is distinct from the semantic value of the token.
*
* @see #getValue()
*/
public String getText()
{
return text;
}
/**
* Returns the semantic value of this token.
*
* For strings, this is the parsed String.
* For integers, this is an Integer object.
* For other token types, as appropriate.
*
* @see #getText()
*/
public Object getValue()
{
return value;
}
/**
* Returns a description of this token, for debugging purposes.
*/
public String ToString()
{
StringBuilder buf = new StringBuilder();
buf.Append('[').Append(getTokenName(type));
if(line != -1) {
buf.Append('@').Append(line);
if(column != -1)
buf.Append(',').Append(column);
}
buf.Append("]:");
if(text != null)
buf.Append('"').Append(text).Append('"');
else if(type > 3 && type < 256)
buf.Append((char)type);
else
buf.Append('<').Append(type).Append('>');
if(value != null)
buf.Append('=').Append(value);
return buf.ToString();
}
/**
* Returns the descriptive name of the given token type.
*
* This is mostly used for stringification and debugging.
*/
public static String getTokenName(int type)
{
if(type < 0)
return "Invalid" + type;
if(type >= names.Length)
return "Invalid" + type;
if(names[type] == null)
return "Unknown" + type;
return names[type];
}
/** The token type AND_EQ. */
public const int AND_EQ = 257;
/** The token type ARROW. */
public const int ARROW = 258;
/** The token type CHARACTER. */
public const int CHARACTER = 259;
/** The token type CCOMMENT. */
public const int CCOMMENT = 260;
/** The token type CPPCOMMENT. */
public const int CPPCOMMENT = 261;
/** The token type DEC. */
public const int DEC = 262;
/** The token type DIV_EQ. */
public const int DIV_EQ = 263;
/** The token type ELLIPSIS. */
public const int ELLIPSIS = 264;
/** The token type EOF. */
public const int EOF = 265;
/** The token type EQ. */
public const int EQ = 266;
/** The token type GE. */
public const int GE = 267;
/** The token type HASH. */
public const int HASH = 268;
/** The token type HEADER. */
public const int HEADER = 269;
/** The token type IDENTIFIER. */
public const int IDENTIFIER = 270;
/** The token type INC. */
public const int INC = 271;
/** The token type INTEGER. */
public const int INTEGER = 272;
/** The token type LAND. */
public const int LAND = 273;
/** The token type LAND_EQ. */
public const int LAND_EQ = 274;
/** The token type LE. */
public const int LE = 275;
/** The token type LITERAL. */
public const int LITERAL = 276;
/** The token type LOR. */
public const int LOR = 277;
/** The token type LOR_EQ. */
public const int LOR_EQ = 278;
/** The token type LSH. */
public const int LSH = 279;
/** The token type LSH_EQ. */
public const int LSH_EQ = 280;
/** The token type MOD_EQ. */
public const int MOD_EQ = 281;
/** The token type MULT_EQ. */
public const int MULT_EQ = 282;
/** The token type NE. */
public const int NE = 283;
/** The token type NL. */
public const int NL = 284;
/** The token type OR_EQ. */
public const int OR_EQ = 285;
/** The token type PASTE. */
public const int PASTE = 286;
/** The token type PLUS_EQ. */
public const int PLUS_EQ = 287;
/** The token type RANGE. */
public const int RANGE = 288;
/** The token type RSH. */
public const int RSH = 289;
/** The token type RSH_EQ. */
public const int RSH_EQ = 290;
/** The token type STRING. */
public const int STRING = 291;
/** The token type SUB_EQ. */
public const int SUB_EQ = 292;
/** The token type WHITESPACE. */
public const int WHITESPACE = 293;
/** The token type XOR_EQ. */
public const int XOR_EQ = 294;
/** The token type M_ARG. */
public const int M_ARG = 295;
/** The token type M_PASTE. */
public const int M_PASTE = 296;
/** The token type M_STRING. */
public const int M_STRING = 297;
/** The token type P_LINE. */
public const int P_LINE = 298;
/** The token type INVALID. */
public const int INVALID = 299;
/**
* The number of possible semantic token types.
*
* Please note that not all token types below 255 are used.
*/
public const int _TOKENS = 300;
/** The position-less space token. */
/* pp */
public static readonly Token space = new Token(WHITESPACE, -1, -1, " ");
private static readonly String[] names = new String[_TOKENS];
private static readonly String[] texts = new String[_TOKENS];
static Token()
{
for(int i = 0; i < 255; i++) {
texts[i] = ((char)i).ToString();
names[i] = texts[i];
}
texts[AND_EQ] = "&=";
texts[ARROW] = "->";
texts[DEC] = "--";
texts[DIV_EQ] = "/=";
texts[ELLIPSIS] = "...";
texts[EQ] = "==";
texts[GE] = ">=";
texts[HASH] = "#";
texts[INC] = "++";
texts[LAND] = "&&";
texts[LAND_EQ] = "&&=";
texts[LE] = "<=";
texts[LOR] = "||";
texts[LOR_EQ] = "||=";
texts[LSH] = "<<";
texts[LSH_EQ] = "<<=";
texts[MOD_EQ] = "%=";
texts[MULT_EQ] = "*=";
texts[NE] = "!=";
texts[NL] = "\n";
texts[OR_EQ] = "|=";
/* We have to split the two hashes or Velocity eats them. */
texts[PASTE] = "#" + "#";
texts[PLUS_EQ] = "+=";
texts[RANGE] = "..";
texts[RSH] = ">>";
texts[RSH_EQ] = ">>=";
texts[SUB_EQ] = "-=";
texts[XOR_EQ] = "^=";
names[AND_EQ] = "AND_EQ";
names[ARROW] = "ARROW";
names[CHARACTER] = "CHARACTER";
names[CCOMMENT] = "CCOMMENT";
names[CPPCOMMENT] = "CPPCOMMENT";
names[DEC] = "DEC";
names[DIV_EQ] = "DIV_EQ";
names[ELLIPSIS] = "ELLIPSIS";
names[EOF] = "EOF";
names[EQ] = "EQ";
names[GE] = "GE";
names[HASH] = "HASH";
names[HEADER] = "HEADER";
names[IDENTIFIER] = "IDENTIFIER";
names[INC] = "INC";
names[INTEGER] = "INTEGER";
names[LAND] = "LAND";
names[LAND_EQ] = "LAND_EQ";
names[LE] = "LE";
names[LITERAL] = "LITERAL";
names[LOR] = "LOR";
names[LOR_EQ] = "LOR_EQ";
names[LSH] = "LSH";
names[LSH_EQ] = "LSH_EQ";
names[MOD_EQ] = "MOD_EQ";
names[MULT_EQ] = "MULT_EQ";
names[NE] = "NE";
names[NL] = "NL";
names[OR_EQ] = "OR_EQ";
names[PASTE] = "PASTE";
names[PLUS_EQ] = "PLUS_EQ";
names[RANGE] = "RANGE";
names[RSH] = "RSH";
names[RSH_EQ] = "RSH_EQ";
names[STRING] = "STRING";
names[SUB_EQ] = "SUB_EQ";
names[WHITESPACE] = "WHITESPACE";
names[XOR_EQ] = "XOR_EQ";
names[M_ARG] = "M_ARG";
names[M_PASTE] = "M_PASTE";
names[M_STRING] = "M_STRING";
names[P_LINE] = "P_LINE";
names[INVALID] = "INVALID";
}
}
}

54
TokenSnifferSource.cs Normal file
Просмотреть файл

@ -0,0 +1,54 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.anarres.cpp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import static org.anarres.cpp.Token.*;
@Deprecated
/* pp */ class TokenSnifferSource extends Source {
private List<Token> target;
/* pp */ TokenSnifferSource(List<Token> target) {
this.target = target;
}
public Token token()
throws IOException,
LexerException {
Token tok = getParent().token();
if (tok.getType() != EOF)
target.add(tok);
return tok;
}
public String toString() {
return getParent().toString();
}
}

33
VirtualFile.cs Normal file
Просмотреть файл

@ -0,0 +1,33 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
namespace CppNet {
/**
* An extremely lightweight virtual file interface.
*/
public interface VirtualFile {
// public String getParent();
bool isFile();
string getPath();
string getName();
VirtualFile getParentFile();
VirtualFile getChildFile(string name);
Source getSource();
}
}

30
VirtualFileSystem.cs Normal file
Просмотреть файл

@ -0,0 +1,30 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
namespace CppNet
{
/**
* An extremely lightweight virtual file system interface.
*/
public interface VirtualFileSystem
{
VirtualFile getFile(String path);
VirtualFile getFile(String dir, String name);
}
}

38
Warning.cs Normal file
Просмотреть файл

@ -0,0 +1,38 @@
/*
* Anarres C Preprocessor
* Copyright (c) 2007-2008, Shevek
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
namespace CppNet
{
/**
* Warning classes which may optionally be emitted by the Preprocessor.
*/
[Flags]
public enum Warning
{
NONE = 0,
TRIGRAPHS = 1 << 0,
// TRADITIONAL,
IMPORT = 1 << 1,
UNDEF = 1 << 2,
UNUSED_MACROS = 1 << 3,
ENDIF_LABELS = 1 << 4,
ERROR = 1 << 5,
// SYSTEM_HEADERS
}
}