플랫폼 간 개발을 위한 CSCS 스크립팅 언어 사용
게시 됨: 2022-03-10우리의 목표는 플랫폼을 구축하는 것이 아닙니다. 모두 교차하는 것입니다.
- 마크 주커 버그
CSCS(Customized Scripting in C#)는 C#으로 구현된 오픈 소스 스크립팅 언어입니다. 문법적으로는 JavaScript와 매우 유사하지만 Python과도 몇 가지 유사합니다. 이러한 유사점 중 일부는 잘 알려진 if…elif…else
구문의 키워드이며 Python에서와 동일한 변수 범위 정의를 갖습니다(예: if
블록 내부 또는 루프 내부에 정의된 변수는 외부에서도 볼 수 있음) .
JavaScript 및 Python과 달리 CSCS의 변수 및 함수는 대소문자를 구분하지 않습니다. CSCS의 주요 목표는 개발자가 가능한 한 적은 양의 코드를 작성할 수 있도록 하는 것입니다 . 또한 iOS 및 Android 개발에 동일한 코드가 사용됩니다. 또한 CSCS는 Windows, Mac 및 Unity 개발에 사용할 수 있습니다.
참고 : 여기에서 Microsoft가 Maquette 제품(Unity 기반)에서 CSCS를 사용하는 방법에 대해 자세히 알아볼 수 있습니다.
CSCS는 C# 소스 코드를 Visual Studio Xamarin 프로젝트에 포함하여 프로젝트에 추가할 수 있습니다. 대부분의 다른 언어와 달리 CSCS 소스 코드에 대한 완전한 소유권이 있으며 해당 기능을 쉽게 추가하거나 수정할 수 있습니다. 이 기사의 뒷부분에서 이에 대한 예를 공유하겠습니다.
또한 CSCS를 시작하는 방법과 다른 기사에서 다룬 고급 기능을 사용하는 방법을 배울 것입니다. 이러한 기능 중 JSON 문자열 구문 분석을 통해 웹 요청을 통해 웹 서비스에 액세스하고 iOS 및 Android에서도 SQLite를 사용할 것입니다.
시작하는 가장 쉬운 방법은 CSCS를 사용하여 프로젝트 샘플을 다운로드하고 start.cscs 파일로 재생을 시작하는 것입니다. 이것이 우리가 다음 섹션에서 할 일입니다: 기본 GUI 및 이벤트를 사용하여 iOS/Android 앱 만들기.
“안녕, 월드!” CSCS에서
몇 개의 위젯으로 화면을 구성하는 CSCS 코드의 비교적 간단한 예부터 시작하겠습니다.
AutoScale(); SetBackgroundColor("light_green"); locLabelText = GetLocation("ROOT", "CENTER", "ROOT", "TOP"); AddLabel(locLabelText, "labelText", "Welcome " + _DEVICE_INFO_ + " " + _VERSION_INFO_ + " User!", 600, 100); locTextEdit = GetLocation("ROOT", "LEFT", labelText, "BOTTOM"); AddTextEdit(locTextEdit, "textEdit", "Your name", 320, 80); locButton = GetLocation(textEdit,"RIGHT",textEdit, "CENTER"); AddButton(locButton, "buttonHi", "Hello", 160, 80); function buttonHi_click(sender, arg) { name = getText(textEdit); msg = name != "" ? "Hello, "+ name + "!" : "Hello, World!"; AlertDialog("My Great App", msg); }
아래 이미지는 "Hello" 버튼을 클릭하고 "텍스트 편집" 필드에 아무 것도 입력하지 않은 후의 iPhone 및 Android 장치의 결과 사용자 인터페이스를 보여줍니다.

위의 코드를 간단히 살펴보겠습니다. AutoScale()
함수 호출로 시작하고 그 역할은 파서에 위젯 크기가 화면 크기에 상대적이라는 것을 알려주는 것입니다. 화면). 이 설정은 위젯별로 재정의될 수도 있습니다.
버튼 클릭 시 특별한 핸들러를 생성할 필요가 없습니다. 이름이 widgetName_click()
인 함수를 정의하면 사용자가 widgetName
이라는 위젯을 클릭할 때 핸들러로 사용됩니다(버튼일 필요는 없으며 실제로 모든 위젯이 될 수 있음). 이것이 사용자가 버튼을 클릭하는 즉시 buttonHi_click()
함수가 트리거되는 이유입니다.
GUI가 완전히 코드로 구성되어 있음을 눈치채셨을 것입니다. 이것은 위젯을 추가할 때 상대적인 위젯 위치를 제공하여 수행됩니다. 위치 명령의 일반적인 형식은 다음과 같습니다.
location = GetLocation(WidgetX, HorizontalPlacement, WidgetY, VerticalPlacement, deltaX=0, deltaY=0, autoResize=true);
따라서 화면의 다른 위젯에 상대적인 위젯을 배치할 수 있습니다. 위젯의 특별한 경우는 메인 화면을 의미하는 "ROOT" 위젯입니다.
위치를 생성한 후 다음 함수에 대한 인수로 제공해야 합니다.
-
AddLabel
, -
AddButton
, -
AddCombobox
, -
AddStepper
, -
AddListView
, -
AddTextView
, -
AddStepper
, -
AddImageView
, -
AddSlider
, -
AddPickerView
, - 등등.
위의 모든 항목은 동일한 구조를 갖습니다.
AddButton(location, newWidgetname, initialValue, width, height);
AutoScale()
CSCS 명령이 이전에 실행된 경우 위젯 너비와 높이는 화면 크기에 상대적입니다. 또한 초기 값(버튼의 경우)은 그 위에 표시되는 텍스트입니다. 이것은 SetText(widgetName, newText)
를 호출하여 언제든지 변경할 수 있습니다.
Visual Studio Code를 사용하여 CSCS 디버그
Visual Studio Code를 사용하여 CSCS 스크립트를 디버그할 수도 있습니다. Android 및 iOS용 앱을 모두 개발하려면 Mac을 사용해야 합니다. Visual Studio Code를 설치한 후 CSCS 디버거 및 REPL 확장을 설치합니다.
확장을 사용하려면 start.cscs
CSCS 스크립트의 아무 곳에나 다음 코드 줄을 추가하세요.
StartDebugger();
아래의 다음 이미지는 Visual Studio Code를 사용하여 "Hello, World!"의 기능을 디버그하고 변경하는 방법을 보여줍니다. 이전 섹션에서 개발한 앱입니다. 다음 예제에서는 기존 레이아웃에 레이블과 버튼을 즉시 추가할 것입니다.
이렇게 하려면 파서에서 실행할 코드를 선택하고 Ctrl + 8 을 누르기만 하면 됩니다. 결과적으로 화면 중앙에 레이블과 버튼이 추가됩니다. 또한 각 버튼을 클릭할 때 현재 시간으로 새 레이블을 업데이트하는 버튼 핸들러를 추가합니다.

CSCS에서 SQLite 사용
SQLite는 관계형 데이터베이스의 ACID(Atomicity, Consistency, Isolation, Durability) 유형으로 Richard Hipp에 의해 개발되었습니다(첫 번째 버전은 2000년 출시). Microsoft SQL Server 또는 Oracle Database와 같은 다른 관계형 데이터베이스와 달리 내장되어 있습니다. (장치뿐만 아니라 최종 프로그램에도 포함됩니다.) 크기가 500KB 미만인 매우 컴팩트한 라이브러리로 프로그램에 포함됩니다. 그러나 두 앱(동일 개발자가 출시한)은 DB 파일 경로가 두 앱에 모두 알려진 경우 동일한 SQLite DB를 읽을 수 있습니다.
SQLite의 장점은 iOS나 Android 기기에 별도의 설치 없이 사용할 수 있다는 것입니다. 단점은 분명히 "일반" DB만큼 많은 데이터를 보유할 수 없고 유형이 약하다는 것입니다(즉, 정수 대신 문자열을 삽입할 수 있습니다. 그러면 실패 시 정수 또는 0으로 변환됩니다). 한편 후자도 장점으로 볼 수 있다.
SQLite는 추가 import 문 없이 CSCS에서 쉽게 사용할 수 있습니다. 다음은 CSCS에서 사용되는 주요 SQLite 기능에 대한 개요를 얻는 데 도움이 되는 표입니다.
명령 | 설명 |
---|---|
SQLInit(DBName) | 데이터베이스를 초기화하거나 후속 DB 문과 함께 사용할 데이터베이스를 설정합니다. |
SQLDBExists(DBName) | DB가 초기화되었는지 확인합니다. 또한 후속 DB 문과 함께 사용할 데이터베이스를 설정합니다. |
SQLQuery(query) | SQL 쿼리(select 문)를 실행합니다. 레코드가 있는 테이블을 반환합니다. |
SQLNonQuery(nonQuery) | 업데이트, 생성 또는 삭제 문과 같이 쿼리가 아닌 SQL을 실행합니다. 영향을 받는 레코드 수를 반환합니다. |
SQLInsert(tableName, columnList, data) | 전달된 레코드의 데이터 테이블을 지정된 DB 테이블에 삽입합니다. columnList 인수의 구조는 colName1,colName2,…,colNameN |
표 1: CSCS의 SQLite 명령
SQLInit()
및 SQLDBExists()
함수가 일반적으로 사용되는 방법은 다음과 같습니다.
DBName = "myDB.db1"; if (!SQLDBExists(DBName)) { create = "CREATE TABLE [Data] (Symbol ntext, Low real, High real, Close real, Volume real, Stamp text DEFAULT CURRENT_TIMESTAMP)"; SQLNonQuery(create); } SQLInit(DBName);
나중에 SQLite 데이터베이스에 데이터를 선택하고 삽입하는 방법에 대한 더 많은 예를 볼 것입니다. 웹 서비스에서 추출한 주식 데이터를 로컬 SQLite 데이터베이스에 쓰는 방법의 예를 보여 드리겠습니다.
CSCS에 사용자 지정 기능 추가
이 섹션에서는 CSCS 기능을 확장하는 방법을 살펴보겠습니다. 예를 들어 아래에서 CSCS 절전 기능의 기존 구현을 볼 것입니다.
사용자 지정 기능을 추가하려면 ParserFunction
클래스에서 파생하고 해당 Evaluate()
메서드를 재정의하고 이 클래스를 파서에 등록하여 새 클래스를 만들기만 하면 됩니다. 다음은 짧은 버전입니다(오류 검사 없음).
class SleepFunction : ParserFunction { protected override Variable Evaluate(ParsingScript script) { List args = script.GetFunctionArgs(); int sleepms = Utils.GetSafeInt(args, 0); Thread.Sleep(sleepms); return Variable.EmptyInstance; } }
class SleepFunction : ParserFunction { protected override Variable Evaluate(ParsingScript script) { List args = script.GetFunctionArgs(); int sleepms = Utils.GetSafeInt(args, 0); Thread.Sleep(sleepms); return Variable.EmptyInstance; } }
파서에 클래스 등록은 다음 명령을 통해 초기화 단계의 어느 곳에서나 수행할 수 있습니다.

ParserFunction.RegisterFunction("Sleep", new SleepFunction());
그게 다야! 이제 "Sleep" 토큰이 파서에 의해 추출되자마자 SleepFunction
클래스의 Evaluate()
메서드가 호출됩니다.
CSCS는 대소문자를 구분하지 않습니다(핵심 제어 흐름 문 제외: if
, elif
, else
, for
, while
, function
, include
, new
, class
, return
, try
, throw
, catch
, break
, continue
). 즉, "sleep(100)" 또는 "Sleep(100)"을 입력할 수 있습니다. 두 호출 모두 100밀리초 동안 실행 스레드를 일시 중단합니다.
CSCS에서 JSON 처리
JSON(JavaScript Object Notation)은 속성-값 쌍과 배열 유형 쌍으로 구성된 경량 데이터 교환 형식입니다. 2000년대 초 Douglas Crockford에 의해 개발되었습니다(SQLite도 등장한 거의 같은 시기에).
이 섹션에서는 CSCS를 사용하여 JSON을 구문 분석하는 방법을 배웁니다.
JSON 문자열을 구문 분석하는 CSCS 함수는 GetVariableFromJSON(jsonText)
입니다. 이 함수는 키가 JSON 문자열의 속성인 해시 테이블을 반환합니다.
JSON 문자열의 다음 예를 고려하십시오.
jsonString = '{ "eins" : 1, "zwei" : "zweiString", "mehr" : { "uno": "dos" }, "arrayValue" : [ "une", "deux" ] }';
호출 후:
a = GetVariableFromJSON();
변수 a
다음 값을 갖는 해시 테이블이 됩니다.
a["eins"] = 1 a["zwei"] = "zweiString" a["mehr"]["uno"] = "dos" a["arrayValue"][0] = "une" a["arrayValue"][1] = "deux"
다음 섹션에서는 웹 서비스에서 JSON 문자열을 구문 분석하는 또 다른 예를 볼 것입니다.
SQLite, 웹 요청 및 JSON이 있는 앱의 예
SQLite, 웹 서비스 및 JSON 구문 분석을 사용하는 앱의 경우 Alpha Vantage 웹 서비스를 사용할 것입니다. API 키를 무료로 얻을 수 있지만 무료 버전은 웹 서비스에 분당 5회 이상 액세스할 수 없습니다.
Alpha Vantage를 사용하여 주가를 포함한 다양한 재무 데이터 세트를 추출할 수 있습니다. 이것이 샘플 앱에서 수행할 작업입니다.
아래 이미지는 iOS 및 Android 기기에서 주식 앱이 어떻게 보이는지 보여줍니다.

GUI를 빌드하기 위한 CSCS 코드는 다음과 같습니다.
locLabel = GetLocation("ROOT","CENTER", "ROOT","TOP", 0,30); AddLabel(locLabel, "labelRefresh", "", 480, 60); locSFWidget = GetLocation("ROOT","CENTER", labelRefresh,"BOTTOM"); AddSfDataGrid(locSFWidget, "DataGrid", "", graphWidth, graphHeight); listCols = {"Symbol","string", "Low","number", "High", "number", "Close","number", "Volume","number"}; AddWidgetData(DataGrid, listCols, "columns"); colWidth = {17, 19, 19, 19, 26}; AddWidgetData(DataGrid, colWidth, "columnWidth"); locButton = GetLocation("ROOT","CENTER",DataGrid,"BOTTOM"); AddButton(locButton, "buttonRefresh", "Refresh", 160, 80); locLabelError = GetLocation("ROOT","CENTER","ROOT","BOTTOM"); AddLabel(locLabelError, "labelError", "", 600, 160); SetFontColor(labelError, "red"); AlignText(labelError, "center"); getDataFromDB();
getDataFromDB()
메서드는 SQLite 데이터베이스에서 모든 데이터를 추출합니다. 다음과 같이 정의된 SQL 쿼리를 사용합니다.
query = "SELECT Symbol, Low, High, Close, Volume, DATETIME(Stamp, 'localtime') as Stamp FROM Data ORDER BY Stamp DESC LIMIT 5;";
getDataFromDB()
구현에 대한 아래 코드를 살펴보십시오.
function getDataFromDB() { results = SQLQuery(query); for (i = 1; i < results.Size; i++) { vals = results[i]; stock = vals[0]; low = Round(vals[1], 2); high = Round(vals[2], 2); close = Round(vals[3], 2); volume = Round(vals[4], 2); refresh = vals[5]; stockData = {stock, low, high, close, volume}; AddWidgetData(DataGrid, stockData, "item"); } SetText(labelRefresh, "DB Last Refresh: " + refresh); lockGui(false); }
이제 Alpha Vantage 웹 서비스에서 데이터를 얻는 방법을 살펴보겠습니다. 먼저 데이터를 초기화합니다.
baseURL = "https://www.alphavantage.co/query? " + "function=TIME_SERIES_DAILY&symbol="; apikey = "Y12T0TY5EUS6BC5F"; stocks = {"MSFT", "AAPL", "GOOG", "FB", "AMZN"}; totalStocks = stocks.Size;
다음으로 사용자가 "새로고침" 버튼을 클릭하는 즉시 주식을 하나씩 로드합니다.
function buttonRefresh_click(object, arg) { lockGui(); SetText(labelRefresh, "Loading ..."); SetText(labelError, ""); ClearWidget(DataGrid); loadedStocks = 0; getData(stocks[loadedStocks]); } function getData(symbol) { stockUrl = baseURL + symbol + "&apikey=" + apikey; WebRequest("GET", stockUrl, "", symbol, "OnSuccess", "OnFailure"); }
다음은 웹 서비스에서 데이터를 가져오기 위해 사용할 주요 CSCS 기능입니다.
WebRequest("GET", stockUrl, "", symbol, "OnSuccess", "OnFailure");
마지막 두 매개변수는 웹 요청 완료 시 호출할 함수입니다. 예를 들어, 실패의 경우 다음 CSCS 함수가 호출됩니다.
function OnFailure(object, errorCode, text) { SetText(labelError, text); lockGui(false); }
결과적으로 사용자는 아래와 같은 오류 메시지를 받게 됩니다.

그러나 모든 것이 좋다면 JSON 문자열을 구문 분석하고 그 내용을 SQLite DB에 삽입할 것입니다.
function OnSuccess(object, errorCode, text) { jsonFromText = GetVariableFromJSON(text); metaData = jsonFromText[0]; result = jsonFromText[1]; symbol = metaData["2. Symbol"]; lastRefreshed = metaData["3. Last Refreshed"]; allDates = result.keys; dateData = result[allDates[0]]; high = Round(dateData["2. high"], 2); low = Round(dateData["3. low"], 2); close = Round(dateData["4. close"], 2); volume = dateData["5. volume"]; stockData = {symbol, low, high, close, volume}; SQLInsert("Data","Symbol,Low,High,Close,Volume",stockData); if (++loadedStocks >= totalStocks) { getDataFromDB(); } else { getData(stocks[loadedStocks]); } }
위의 해시 테이블에서 다른 필드에 액세스하는 방법을 이해하기 위해 Alpha Vantage 웹 요청에서 수신된 실제 문자열을 살펴보겠습니다.
{ "Meta Data": { "1. Information": "Daily Prices (open, high, low, close) and Volumes", "2. Symbol": "MSFT", "3. Last Refreshed": "2019-10-02 14:23:20", "4. Output Size": "Compact", "5. Time Zone": "US/Eastern" }, "Time Series (Daily)": { "2019-10-02": { "1. open": "136.3400", "2. high": "136.3700", "3. low": "133.5799", "4. close": "134.4100", "5. volume": "11213086" }, … } }
보시다시피 추출된 모든 날짜로 구성된 allDates
배열의 첫 번째 요소로 최신 날짜를 얻습니다.
결론
프로젝트에 CSCS를 추가하는 것은 쉽습니다. 샘플 Xamarin 프로젝트에서 수행한 것처럼 CSCS의 소스 코드를 프로젝트에 모듈로 포함하기만 하면 됩니다.
프로젝트에서 CSCS 스크립팅 언어를 사용하고 확장합니까? 아래에 의견을 남겨주세요. 기꺼이 답변을 드리겠습니다!
추가 읽기
CSCS 언어를 조금 더 탐구하고 싶다면 다음 주제에 대해 작성한 기사 중 일부를 참조하십시오.
- "C#의 분할 및 병합 식 파서", MSDN Magazine(2015년 10월)
- "C#의 사용자 지정 가능한 스크립팅", MSDN Magazine(2016년 2월)
- "맞춤형 스크립팅 언어를 사용하여 기본 모바일 앱 작성", MSDN Magazine(2018년 2월)
- "CSCS: C#의 사용자 지정 스크립팅", GitHub
- "기능적 스크립팅 언어로 플랫폼 간 네이티브 앱 개발", CODE Magazine
- "사용자 정의 언어를 간결하게 구현"(eBook)
- "기능 언어로 네이티브 모바일 앱을 간결하게 작성"(eBook)
추가 리소스로 CSCS의 기능을 미리 컴파일하여 CSCS 성능을 개선할 수 있는 방법을 읽는 것이 좋습니다.