Skip to content

Instantly share code, notes, and snippets.

@jakewitcher
Last active February 22, 2020 18:17
Show Gist options
  • Save jakewitcher/8e1f14314580c514279501133f063322 to your computer and use it in GitHub Desktop.
Save jakewitcher/8e1f14314580c514279501133f063322 to your computer and use it in GitHub Desktop.
Using FParsec to parse local variable declarations in a Sanscript script and then only returning the array local variables.
//Below is an example of the Sanscript code that serves as the target for this parser.
//(Sanscript is an old scripting language from the 90s)
//There would be additional code in the file as well, the parser ignores everything before and after the local variables are declared
//and then only returns the array variables.
//--------------------------------------------------------------------------------------------------------------------
//local decimal retail_price,sale_price[12],cost[12],sum,local_taxes[12],federal_taxes[12],state_taxes[12],
// mileage[52],fuel_cost[52],capacity;
//local string customer_name,customer_id, order_ids[24];
//local 'Custom Type' delivery_dates[12], order_dates[24];
//--------------------------------------------------------------------------------------------------------------------
open FParsec
type LocalArray =
{ Type: string
Name: string
ArraySize: int }
type UserState = unit
type Parser<'t> = Parser<'t, UserState>
module Option =
let apply ma mf =
match mf, ma with
| Some f, Some a -> Some (f a)
| _ -> None
let isType c = isLetter c
let isCustomType c = isLetter c || isDigit c || isAnyOf " /_-" c
let isIdentifier c = isLetter c || isDigit c || c = '_'
let ws = spaces
let plocal: Parser<_> = pstring "local" .>> ws
let pcustomType: Parser<_> =
between (pchar '\'')
(pchar '\'')
(many1Satisfy isCustomType)
let ptype: Parser<_> =
many1Satisfy isType
<|> pcustomType
.>> ws
let pname: Parser<_> = many1Satisfy isIdentifier
let parrsize: Parser<_> =
between (pchar '[')
(pchar ']')
pint32
let toLocalArrayVars (varType, variables) =
let go state ele =
match snd ele with
| Some arrSize ->
{ Type = varType; Name = fst ele; ArraySize = arrSize } :: state
| None ->
state
variables
|> List.fold go []
let plocalvar =
tuple2 (plocal >>. ptype)
(sepBy (pname .>>. opt parrsize) (pchar ',' .>> ws) .>> pchar ';' .>> ws)
|>> toLocalArrayVars
let plocalvars =
skipCharsTillString "local" false 10000
>>. many plocalvar
|>> List.concat
let runParser p str =
match run p str with
| Success(result, _, _) -> Some result
| _ -> None
let localArrayVarsMap arrayVars =
arrayVars
|> List.map (fun arrayVar ->
arrayVar.Name, arrayVar)
|> Map.ofList
let findLocalArrayVars script =
script
|> runParser plocalvars
|> Option.map localArrayVarsMap
|> Option.defaultValue Map.empty
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment