Scanspec

This feature is experimental. Please share your feedback and report bugs through Toph Community.

Scanspec and Scanlib, the Go package that powers all this, are both open source and available on GitHub.

Why Scanspec?

Scanspec solves two problems for Toph. Scanspec validates input files as you design problems on Drafts. And, Toph uses Scanspec to generate input code in different programming languages.

Let’s say we have N problems in the archive and M programmming languages that we want to provide input code template for. We could go the N × M route, and write a template for each programming language for each problem. But with Scanspec, we simply need to write a Scanspec for each problem and have a generator for each programming language type.

Getting Started

You are designing a problem that involves reading two integers from the input, and printing out their sum. Each input file is expected to contain exactly one line with two integers separated by a single space. The Scanspec for such an input file would look like this:

1
2
3
4
var A, B int
scan A, B
eol
eof

This tells Scanlib to declare two variables: A and B. Then to scan the two variables from the input. Finally to ensure that the end of line (EOL) and end of file (EOF) has been reached.

Note that the scan statements do not require any format specification. That is because the format specification is inferred from the variable types as declared. You can find a list of variable types supported by Scanspec here.

Scanlib can take this code and generate the equivalent input code in C++:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <iostream>

using namespace std;

int main() {
	int A, B;
	cin >> A;
	cin >> B;
	
	return 0;
}

… and in Python:

A, B = map(int, input().split())

We plan to add support for more generators in the near future.

Checking Constraints

You can take this one step further and add checks for the values that are scanned. If your problem garantuees that A and B will be between 0 and 50, then you may add a check statement as follows:

1
2
3
4
5
var A, B int
scan A, B
check A >= 0, A < 50, B >= 0, B < 50
eol
eof

Any test case where the input file doesn’t adhere to these constraints will be flagged.

Control Flow

A “for” statement has the following form:

1
2
3
"for" index ":=" low "..." high
  block
"end"

The block is repeated from index = low while index < high.

Here is an example Scanspec that reads two integers, followed by an array of string:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var R, C int
scan R, C
check R >= 1, R < 25, C >= 1, C < 25
eol
var G [R]string
for i := 0 ... R
	scan G[i]
	check len(G[i]) == C
	check re(G[i], "^[*.]+$")
	eol
end
eof

The above example is for inputs like this:

1
2
3
4
3 5
**...
..*..
....*

Note the two functions used in this example:

  • len(a): Returns the length of array a.
  • re(s, x): Returns true if string s matches regular expression x.

A list of built-in functions supported by Scanspec can be found here.


  • Published February 11, 2021

Search