From 506625791293eb8181e5beaa42ca93aafb3476e3 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 12 Jun 2025 02:18:27 -0500 Subject: [PATCH] Initial commit checkpoint only --- .gitignore | 407 +++++++++++++++++++++++++++++++++ src/.config/dotnet-tools.json | 13 ++ src/core/FunctionArgument.cs | 14 ++ src/core/FunctionValue.cs | 15 ++ src/core/ICodedFunction.cs | 23 ++ src/core/InputInterpreter.cs | 7 + src/core/ValueType.cs | 15 ++ src/core/cocor/Interpreter.atg | 143 ++++++++++++ src/core/cocor/Parser.frame | 156 +++++++++++++ src/core/cocor/Scanner.frame | 381 ++++++++++++++++++++++++++++++ src/core/core.csproj | 14 ++ src/cs-mic.sln | 28 +++ src/setup.ps1 | 3 + 13 files changed, 1219 insertions(+) create mode 100644 .gitignore create mode 100644 src/.config/dotnet-tools.json create mode 100644 src/core/FunctionArgument.cs create mode 100644 src/core/FunctionValue.cs create mode 100644 src/core/ICodedFunction.cs create mode 100644 src/core/InputInterpreter.cs create mode 100644 src/core/ValueType.cs create mode 100644 src/core/cocor/Interpreter.atg create mode 100644 src/core/cocor/Parser.frame create mode 100644 src/core/cocor/Scanner.frame create mode 100644 src/core/core.csproj create mode 100644 src/cs-mic.sln create mode 100644 src/setup.ps1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f16e0d --- /dev/null +++ b/.gitignore @@ -0,0 +1,407 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +[Aa][Rr][Mm]64[Ee][Cc]/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Approval Tests result files +*.received.* + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.idb +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +# but not Directory.Build.rsp, as it configures directory-level build defaults +!Directory.Build.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# AWS SAM Build and Temporary Artifacts folder +.aws-sam + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp \ No newline at end of file diff --git a/src/.config/dotnet-tools.json b/src/.config/dotnet-tools.json new file mode 100644 index 0000000..ef58252 --- /dev/null +++ b/src/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "cocor": { + "version": "2014.12.25", + "commands": [ + "coco" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/src/core/FunctionArgument.cs b/src/core/FunctionArgument.cs new file mode 100644 index 0000000..c4c33cd --- /dev/null +++ b/src/core/FunctionArgument.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace csmic +{ + public class FunctionArgument + { + public required string Name { get; set; } + public required FunctionValue Value { get; set; } + } +} diff --git a/src/core/FunctionValue.cs b/src/core/FunctionValue.cs new file mode 100644 index 0000000..4b9d991 --- /dev/null +++ b/src/core/FunctionValue.cs @@ -0,0 +1,15 @@ +using csmic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace csmic +{ + public class FunctionValue + { + public required csmic.ValueType Type { get; set; } + public object? Value { get; set; } + } +} diff --git a/src/core/ICodedFunction.cs b/src/core/ICodedFunction.cs new file mode 100644 index 0000000..140ce6a --- /dev/null +++ b/src/core/ICodedFunction.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace csmic +{ + public interface ICodedFunction + { + #region Properties + + IEnumerable ExpectedArguments { get; } + + #endregion + + #region Methods + + FunctionValue Execute(params FunctionArgument[] args); + + #endregion + } +} diff --git a/src/core/InputInterpreter.cs b/src/core/InputInterpreter.cs new file mode 100644 index 0000000..3d0ca37 --- /dev/null +++ b/src/core/InputInterpreter.cs @@ -0,0 +1,7 @@ +namespace csmic +{ + public class InputInterpreter + { + + } +} diff --git a/src/core/ValueType.cs b/src/core/ValueType.cs new file mode 100644 index 0000000..f944849 --- /dev/null +++ b/src/core/ValueType.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace csmic +{ + public enum ValueType + { + None, + Numeric, + String + } +} diff --git a/src/core/cocor/Interpreter.atg b/src/core/cocor/Interpreter.atg new file mode 100644 index 0000000..6a2ea0f --- /dev/null +++ b/src/core/cocor/Interpreter.atg @@ -0,0 +1,143 @@ +using csmic; +using System.Text; +using System.Collections.Generic; + +COMPILER INTERPRETER + +/* +* +* Class Structures +* +*/ + +private decimal calcValue = 0; +private string stringValue = string.Empty; + +public decimal CalculatedValue +{ + get + { + return this.calcValue; + } + set + { + this.calcValue = value; + } +} + +public string StringValue +{ + get + { + return this.stringValue + } + set + { + this.stringValue = value + } +} + +private InputInterpreter interpreter = null; + +public InputInterpreter Interpreter +{ + get + { + return this.interpreter; + } + set + { + this.interpreter = value; + } +} + +bool IsFunctionCall() +{ + scanner.ResetPeek(); + Token next = scanner.Peek(); + if (next.kind == _LPAREN && la.kind == _identifier) + return true; + return false; +} + +bool IsCompare() +{ + scanner.ResetPeek(); + Token next = scanner.Peek(); + if (next.kind == _COMPARER) + return true; + return false; +} + +bool IsAssignment() +{ + scanner.ResetPeek(); + Token next = scanner.Peek(); + if (next.val == "::" || next.val == ":=" || next.val == "->") + return true; + return false; +} + +bool IsArrayCall() +{ + scanner.ResetPeek(); + Token next = scanner.Peek(); + if(next.val == "[") + return true; + return false; +} + +/* + * Parser definitions + * + */ + +CHARACTERS + + UpperLetter = 'A'..'Z'. + LowerLetter = 'a'..'z'. + letter = UpperLetter + LowerLetter. + digit = "0123456789" . + cr = '\r' . + lf = '\n' . + tab = '\t' . + PM = "+-" . + NoQuote = ANY - '\"' . + +TOKENS + + identifier = letter { letter | digit}. + sign = PM . + binary = ( '0' | '1' ) { '0' | '1' } ('B' | 'b') . + hex = "0x" ( digit | ('A' | 'B' | 'C' | 'D' | 'E' |'F') | ('a' | 'b' | 'c' | 'd' | 'e' |'f') ) { digit | ('A' | 'B' | 'C' | 'D' | 'E' |'F') | ('a' | 'b' | 'c' | 'd' | 'e' |'f') } . + number = digit { digit }['.' {digit}] [('E'|'e')['+'|'-'] digit {digit}] . + string = "\"" { NoQuote } "\"" . + LPAREN = '(' . + RPAREN = ')' . + COMPARER = "==" | "<" | ">" | "<=" | ">=" . + +IGNORE cr + tab + +/* + * Parser specification + * + */ + + PRODUCTIONS + + INTERPRETER (. + decimal decimalValue = 0; + string stringValue = string.Empty; + bool success = true; + if(this.interpreter == null) + { + return; + } + .) += + + IF(IsCompare()) + Comparison (. this.calcValue = (success == true) ? 1 : 0; .) + | + IF(IsAssignment()) + Assignment \ No newline at end of file diff --git a/src/core/cocor/Parser.frame b/src/core/cocor/Parser.frame new file mode 100644 index 0000000..6878147 --- /dev/null +++ b/src/core/cocor/Parser.frame @@ -0,0 +1,156 @@ +/*---------------------------------------------------------------------- +Compiler Generator Coco/R, +Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz +extended by M. Loeberbauer & A. Woess, Univ. of Linz +with improvements by Pat Terry, Rhodes University + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As an exception, it is allowed to write an extension of Coco/R that is +used as a plugin in non-free software. + +If not otherwise stated, any source code generated by Coco/R (other than +Coco/R itself) does not fall under the GNU General Public License. +----------------------------------------------------------------------*/ +-->begin +using System; + +-->namespace + +public class Parser { +-->constants + const bool _T = true; + const bool _x = false; + const int minErrDist = 2; + + public Scanner scanner; + public Errors errors; + + public Token t; // last recognized token + public Token la; // lookahead token + int errDist = minErrDist; + +-->declarations + + public Parser(Scanner scanner) { + this.scanner = scanner; + errors = new Errors(); + } + + void SynErr (int n) { + if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n); + errDist = 0; + } + + public void SemErr (string msg) { + if (errDist >= minErrDist) errors.SemErr(t.line, t.col, msg); + errDist = 0; + } + + void Get () { + for (;;) { + t = la; + la = scanner.Scan(); + if (la.kind <= maxT) { ++errDist; break; } +-->pragmas + la = t; + } + } + + void Expect (int n) { + if (la.kind==n) Get(); else { SynErr(n); } + } + + bool StartOf (int s) { + return set[s, la.kind]; + } + + void ExpectWeak (int n, int follow) { + if (la.kind == n) Get(); + else { + SynErr(n); + while (!StartOf(follow)) Get(); + } + } + + + bool WeakSeparator(int n, int syFol, int repFol) { + int kind = la.kind; + if (kind == n) {Get(); return true;} + else if (StartOf(repFol)) {return false;} + else { + SynErr(n); + while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) { + Get(); + kind = la.kind; + } + return StartOf(syFol); + } + } + + +-->productions + + public void Parse() { + la = new Token(); + la.val = ""; + Get(); +-->parseRoot + } + + static readonly bool[,] set = { +-->initialization + }; +} // end Parser + + +public class Errors { + public int count = 0; // number of errors detected + public System.IO.TextWriter errorStream = Console.Out; // error messages go to this stream + public string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text + + public virtual void SynErr (int line, int col, int n) { + string s; + switch (n) { +-->errors + default: s = "error " + n; break; + } + errorStream.WriteLine(errMsgFormat, line, col, s); + count++; + } + + public virtual void SemErr (int line, int col, string s) { + errorStream.WriteLine(errMsgFormat, line, col, s); + count++; + } + + public virtual void SemErr (string s) { + errorStream.WriteLine(s); + count++; + } + + public virtual void Warning (int line, int col, string s) { + errorStream.WriteLine(errMsgFormat, line, col, s); + } + + public virtual void Warning(string s) { + errorStream.WriteLine(s); + } +} // Errors + + +public class FatalError: Exception { + public FatalError(string m): base(m) {} +} diff --git a/src/core/cocor/Scanner.frame b/src/core/cocor/Scanner.frame new file mode 100644 index 0000000..9ccf06b --- /dev/null +++ b/src/core/cocor/Scanner.frame @@ -0,0 +1,381 @@ +/*---------------------------------------------------------------------- +Compiler Generator Coco/R, +Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz +extended by M. Loeberbauer & A. Woess, Univ. of Linz +with improvements by Pat Terry, Rhodes University + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As an exception, it is allowed to write an extension of Coco/R that is +used as a plugin in non-free software. + +If not otherwise stated, any source code generated by Coco/R (other than +Coco/R itself) does not fall under the GNU General Public License. +-----------------------------------------------------------------------*/ +-->begin +using System; +using System.IO; +using System.Collections; + +-->namespace + +public class Token { + public int kind; // token kind + public int pos; // token position in bytes in the source text (starting at 0) + public int charPos; // token position in characters in the source text (starting at 0) + public int col; // token column (starting at 1) + public int line; // token line (starting at 1) + public string val; // token value + public Token next; // ML 2005-03-11 Tokens are kept in linked list +} + +//----------------------------------------------------------------------------------- +// Buffer +//----------------------------------------------------------------------------------- +public class Buffer { + // This Buffer supports the following cases: + // 1) seekable stream (file) + // a) whole stream in buffer + // b) part of stream in buffer + // 2) non seekable stream (network, console) + + public const int EOF = char.MaxValue + 1; + const int MIN_BUFFER_LENGTH = 1024; // 1KB + const int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB + byte[] buf; // input buffer + int bufStart; // position of first byte in buffer relative to input stream + int bufLen; // length of buffer + int fileLen; // length of input stream (may change if the stream is no file) + int bufPos; // current position in buffer + Stream stream; // input stream (seekable) + bool isUserStream; // was the stream opened by the user? + + public Buffer (Stream s, bool isUserStream) { + stream = s; this.isUserStream = isUserStream; + + if (stream.CanSeek) { + fileLen = (int) stream.Length; + bufLen = Math.Min(fileLen, MAX_BUFFER_LENGTH); + bufStart = Int32.MaxValue; // nothing in the buffer so far + } else { + fileLen = bufLen = bufStart = 0; + } + + buf = new byte[(bufLen>0) ? bufLen : MIN_BUFFER_LENGTH]; + if (fileLen > 0) Pos = 0; // setup buffer to position 0 (start) + else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid + if (bufLen == fileLen && stream.CanSeek) Close(); + } + + protected Buffer(Buffer b) { // called in UTF8Buffer constructor + buf = b.buf; + bufStart = b.bufStart; + bufLen = b.bufLen; + fileLen = b.fileLen; + bufPos = b.bufPos; + stream = b.stream; + // keep destructor from closing the stream + b.stream = null; + isUserStream = b.isUserStream; + } + + ~Buffer() { Close(); } + + protected void Close() { + if (!isUserStream && stream != null) { + stream.Close(); + stream = null; + } + } + + public virtual int Read () { + if (bufPos < bufLen) { + return buf[bufPos++]; + } else if (Pos < fileLen) { + Pos = Pos; // shift buffer start to Pos + return buf[bufPos++]; + } else if (stream != null && !stream.CanSeek && ReadNextStreamChunk() > 0) { + return buf[bufPos++]; + } else { + return EOF; + } + } + + public int Peek () { + int curPos = Pos; + int ch = Read(); + Pos = curPos; + return ch; + } + + // beg .. begin, zero-based, inclusive, in byte + // end .. end, zero-based, exclusive, in byte + public string GetString (int beg, int end) { + int len = 0; + char[] buf = new char[end - beg]; + int oldPos = Pos; + Pos = beg; + while (Pos < end) buf[len++] = (char) Read(); + Pos = oldPos; + return new String(buf, 0, len); + } + + public int Pos { + get { return bufPos + bufStart; } + set { + if (value >= fileLen && stream != null && !stream.CanSeek) { + // Wanted position is after buffer and the stream + // is not seek-able e.g. network or console, + // thus we have to read the stream manually till + // the wanted position is in sight. + while (value >= fileLen && ReadNextStreamChunk() > 0); + } + + if (value < 0 || value > fileLen) { + throw new FatalError("buffer out of bounds access, position: " + value); + } + + if (value >= bufStart && value < bufStart + bufLen) { // already in buffer + bufPos = value - bufStart; + } else if (stream != null) { // must be swapped in + stream.Seek(value, SeekOrigin.Begin); + bufLen = stream.Read(buf, 0, buf.Length); + bufStart = value; bufPos = 0; + } else { + // set the position to the end of the file, Pos will return fileLen. + bufPos = fileLen - bufStart; + } + } + } + + // Read the next chunk of bytes from the stream, increases the buffer + // if needed and updates the fields fileLen and bufLen. + // Returns the number of bytes read. + private int ReadNextStreamChunk() { + int free = buf.Length - bufLen; + if (free == 0) { + // in the case of a growing input stream + // we can neither seek in the stream, nor can we + // foresee the maximum length, thus we must adapt + // the buffer size on demand. + byte[] newBuf = new byte[bufLen * 2]; + Array.Copy(buf, newBuf, bufLen); + buf = newBuf; + free = bufLen; + } + int read = stream.Read(buf, bufLen, free); + if (read > 0) { + fileLen = bufLen = (bufLen + read); + return read; + } + // end of stream reached + return 0; + } +} + +//----------------------------------------------------------------------------------- +// UTF8Buffer +//----------------------------------------------------------------------------------- +public class UTF8Buffer: Buffer { + public UTF8Buffer(Buffer b): base(b) {} + + public override int Read() { + int ch; + do { + ch = base.Read(); + // until we find a utf8 start (0xxxxxxx or 11xxxxxx) + } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF)); + if (ch < 128 || ch == EOF) { + // nothing to do, first 127 chars are the same in ascii and utf8 + // 0xxxxxxx or end of file character + } else if ((ch & 0xF0) == 0xF0) { + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + int c1 = ch & 0x07; ch = base.Read(); + int c2 = ch & 0x3F; ch = base.Read(); + int c3 = ch & 0x3F; ch = base.Read(); + int c4 = ch & 0x3F; + ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4; + } else if ((ch & 0xE0) == 0xE0) { + // 1110xxxx 10xxxxxx 10xxxxxx + int c1 = ch & 0x0F; ch = base.Read(); + int c2 = ch & 0x3F; ch = base.Read(); + int c3 = ch & 0x3F; + ch = (((c1 << 6) | c2) << 6) | c3; + } else if ((ch & 0xC0) == 0xC0) { + // 110xxxxx 10xxxxxx + int c1 = ch & 0x1F; ch = base.Read(); + int c2 = ch & 0x3F; + ch = (c1 << 6) | c2; + } + return ch; + } +} + +//----------------------------------------------------------------------------------- +// Scanner +//----------------------------------------------------------------------------------- +public class Scanner { + const char EOL = '\n'; + const int eofSym = 0; /* pdt */ +-->declarations + + public Buffer buffer; // scanner buffer + + Token t; // current token + int ch; // current input character + int pos; // byte position of current character + int charPos; // position by unicode characters starting with 0 + int col; // column number of current character + int line; // line number of current character + int oldEols; // EOLs that appeared in a comment; + static readonly Hashtable start; // maps first token character to start state + + Token tokens; // list of tokens already peeked (first token is a dummy) + Token pt; // current peek token + + char[] tval = new char[128]; // text of current token + int tlen; // length of current token + + static Scanner() { + start = new Hashtable(128); +-->initialization + } + + public Scanner (string fileName) { + try { + Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); + buffer = new Buffer(stream, false); + Init(); + } catch (IOException) { + throw new FatalError("Cannot open file " + fileName); + } + } + + public Scanner (Stream s) { + buffer = new Buffer(s, true); + Init(); + } + + void Init() { + pos = -1; line = 1; col = 0; charPos = -1; + oldEols = 0; + NextCh(); + if (ch == 0xEF) { // check optional byte order mark for UTF-8 + NextCh(); int ch1 = ch; + NextCh(); int ch2 = ch; + if (ch1 != 0xBB || ch2 != 0xBF) { + throw new FatalError(String.Format("illegal byte order mark: EF {0,2:X} {1,2:X}", ch1, ch2)); + } + buffer = new UTF8Buffer(buffer); col = 0; charPos = -1; + NextCh(); + } + pt = tokens = new Token(); // first token is a dummy + } + + void NextCh() { + if (oldEols > 0) { ch = EOL; oldEols--; } + else { + pos = buffer.Pos; + // buffer reads unicode chars, if UTF8 has been detected + ch = buffer.Read(); col++; charPos++; + // replace isolated '\r' by '\n' in order to make + // eol handling uniform across Windows, Unix and Mac + if (ch == '\r' && buffer.Peek() != '\n') ch = EOL; + if (ch == EOL) { line++; col = 0; } + } +-->casing1 + } + + void AddCh() { + if (tlen >= tval.Length) { + char[] newBuf = new char[2 * tval.Length]; + Array.Copy(tval, 0, newBuf, 0, tval.Length); + tval = newBuf; + } + if (ch != Buffer.EOF) { +-->casing2 + NextCh(); + } + } + + +-->comments + + void CheckLiteral() { +-->literals + } + + Token NextToken() { + while (ch == ' ' || +-->scan1 + ) NextCh(); +-->scan2 + int recKind = noSym; + int recEnd = pos; + t = new Token(); + t.pos = pos; t.col = col; t.line = line; t.charPos = charPos; + int state; + if (start.ContainsKey(ch)) { state = (int) start[ch]; } + else { state = 0; } + tlen = 0; AddCh(); + + switch (state) { + case -1: { t.kind = eofSym; break; } // NextCh already done + case 0: { + if (recKind != noSym) { + tlen = recEnd - t.pos; + SetScannerBehindT(); + } + t.kind = recKind; break; + } // NextCh already done +-->scan3 + } + t.val = new String(tval, 0, tlen); + return t; + } + + private void SetScannerBehindT() { + buffer.Pos = t.pos; + NextCh(); + line = t.line; col = t.col; charPos = t.charPos; + for (int i = 0; i < tlen; i++) NextCh(); + } + + // get the next token (possibly a token already seen during peeking) + public Token Scan () { + if (tokens.next == null) { + return NextToken(); + } else { + pt = tokens = tokens.next; + return tokens; + } + } + + // peek for the next token, ignore pragmas + public Token Peek () { + do { + if (pt.next == null) { + pt.next = NextToken(); + } + pt = pt.next; + } while (pt.kind > maxT); // skip pragmas + + return pt; + } + + // make sure that peeking starts at the current scan position + public void ResetPeek () { pt = tokens; } + +} // end Scanner diff --git a/src/core/core.csproj b/src/core/core.csproj new file mode 100644 index 0000000..4a634f3 --- /dev/null +++ b/src/core/core.csproj @@ -0,0 +1,14 @@ + + + + net9.0 + cs_mic.core + enable + enable + + + + + + + diff --git a/src/cs-mic.sln b/src/cs-mic.sln new file mode 100644 index 0000000..74f32ae --- /dev/null +++ b/src/cs-mic.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35707.178 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "core", "core\core.csproj", "{5387FF55-3044-4EB4-BB90-AD2E922131C1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6394EDF0-24F7-4B75-B4CE-E5F884EE88AC}" + ProjectSection(SolutionItems) = preProject + setup.ps1 = setup.ps1 + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Description = CS-MIC is a .NET library written in C# designed to give developers easy access to expression parsing. + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5387FF55-3044-4EB4-BB90-AD2E922131C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5387FF55-3044-4EB4-BB90-AD2E922131C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5387FF55-3044-4EB4-BB90-AD2E922131C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5387FF55-3044-4EB4-BB90-AD2E922131C1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/setup.ps1 b/src/setup.ps1 new file mode 100644 index 0000000..d3bcb84 --- /dev/null +++ b/src/setup.ps1 @@ -0,0 +1,3 @@ +Write-Host "Restoring local dotnet tools..." +dotnet tool restore +Write-Host "Done. You can now run: dotnet tool run coco" \ No newline at end of file